はじめに
今回はShaderGraphのCustomFunctionNodeを使ってみようという記事になります。
CustomFunctionNodeは一言で言えば、自分で動作を記述することができるノードということでしょうか。
細かい説明はそれぞれの箇所でしますが、今回目的となるガウシアンフィルタを適用したみた画像は以下になります。

画像の引用 : https://github.com/yoyoyo-yo/Gasyori100knock
そもそもガウシアンフィルタってなんやねんみたいになる方もいるかもしれませんが、以前Compute Shaderを使ってガウシアンフィルタを実装する記事を書いた際に詳しく書いたので、そちらを参照してみてください。
www.hanachiru-blog.com
CustomFunctionNode
Custom Function Nodeとは名前の通り、ノードの挙動をHLSLという言語を用いて記述することができるノードです。
docs.unity3d.com
Custom Function Nodeへのコードの書き込み方としては、stringモードを使用して小さな関数を直接グラフ内に記述する方法と、外部のHLSLのインクルードファイルを参照する方法の2つがあります。
前者はお手軽にShaderGraph内にコードを書くのに対して、後者はShaderGraph外にあるファイルを読み込んできます。

stringモード
まずはstringモードで作ってみましょう。
stringモードでもfileモードでも明示的に入出力の変数を定義しておかなければなりません。
| 種類 | 変数名 | 型 |
|---|---|---|
| tex | 入力 | Texture2D |
| uv | 入力 | Vector2 |
| sam | 入力 | Sampler State |
| color | 出力 | Vector4 |
今回は以上のものを定義してみました。Sampler Stateは見慣れないかもしれませんが,テクスチャの細かい仕様(フィルタリングモードとラップモードの設定)を決めるもので、テクスチャの特定のピクセルの色を取ってくるときなんかに必要になるので入力に入れておきます。
Sampler State ノード | Shader Graph | 10.0.0-preview.27
入出力・関数名を記入したらコードを書いていきます。
color = float4(0, 0, 0, 1); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, -1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, 0)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, 1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, -1)); color += (4.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, 0)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, 1)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, -1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, 0)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, 1));
SAMPLE_TEXTURE2DはUnity側であらかじめ定義されている関数で,Textureの特定の位置にあるピクセルの色を取得できます。
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
HLSLに慣れている方はtex2D()を使いたくなりますが、どうやらエラーが出てしまうようなので注意してください。
あとfloat4であったりint2とかになっているのを初めて見るかたは驚くかもしれませんが、HLSLはC#とは型の書き方が違うからですね。
fileモード
fileモードの場合は拡張子が.hlslとなるおようにファイルを作成(.cgincでもいけるっぽい?)して、参照します。
#ifndef SAMPLE_OUTLINE_INCLUDED #define SAMPLE_OUTLINE_INCLUDED void GaussianFilter_float(Texture2D tex, float2 uv, SamplerState sam, out float4 color) { color = float4(0, 0, 0, 1); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, -1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, 0)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(-1, 1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, -1)); color += (4.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, 0)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(0, 1)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, -1)); color += (2.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, 0)); color += (1.0 / 16.0) * SAMPLE_TEXTURE2D(tex, sam, uv + int2(1, 1)); } #endif
結構御作法が厳しくやりずらいところもありますが、uniform変数を定義できたりとメリットもあるようです。
Custom Function ノード | Shader Graph | 10.0.0-preview.27
細かい箇所は公式ドキュメントをご覧ください。
最終形
作成したCustom Function Nodeを活用して冒頭の貼ったような描画を行えるようにノードを組み合わせます。

さいごに
どんな組み込み関数が定義されているとか、Unity側でどんな関数が定義されているとかがわかりやすくまとまった記事がなかなかないようで大変でした。
マイクロソフトのHLSLのドキュメントは非常に読みづらいし、CustomFunctionNodeでは動作しないような関数等(例えばtex2Dとか)も含まれていてうーんといった感じです。
組み込み関数 - Win32 apps | Microsoft Docs
もっと色々な情報が出回ればShaderGraph界隈も盛り上がるような気もしますが、参入の敷居がやや高めで手が出しづらいような気がします。
天上人の方がお慈悲でわかりやすい記事を書いてくださることを祈ってます。
ではまた。