渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

Unityシェーダのマクロとマルチコンパイル


f:id:esakun:20150730215258g:plain

シェーダ内で#define マクロ名(引数) 処理という文法でマクロを書くことが出来ます。
マクロとはCやC++でよく出てくるインラインで展開されるアレです。

UnityCG.cgincの中身を眺めているとよく出てきます。

眺めることはあっても書いたことはなかったので、試してみました。
またマクロとコンボ技で使用されるマルチコンパイルについても検証しています。

◆サンプルコード

各処理内容を説明していきます。

シェーダ側の処理

1.「SHIBUYA24」というキーワード定義
2.そのキーワードの有無によるシェーダを2種類コンパイル

#pragma multi_compile _ SHIBUYA24

↑ここで_SHIBUYA24というキーワードを定義し、SHIBUYA24キーワードが存在するパターン、存在しないパターンのシェーダをコンパイルするよう指示しています。

◆注意点 1

#pragma multi_compile SHIBUYA24

コメントにも書きましたが、↑このように書いてしまうとSHIBUYA24キーワードが存在するパターンしかコンパイルされませんので、シェーダを切り替えるということができなくなります。

#pragma multi_compile _(アンダースコア) キーワード名 という文法で定義する必要があります。

ちなみにキーワードの頭には_(アンダースコア)が必要です。

◆注意点 2

キーワード名は大文字で記述する必要があります!!(ハマりました)

#pragma multi_compile Hoge・・・・☓ ダメ、キーワードが定義されたことになりません

#pragma multi_compile HOGE・・・・○ 正解

3.SHIBUYA24キーワードの有無によるマクロ挙動の切り替え

#ifdef SHIBUYA24
    #define TEST_MACRO(abc) abc.x = 0;
#else
    #define TEST_MACRO(abc) abc.z = 0;
#endif

このようにマクロを#define マクロ名(引数) 処理という文法で定義し、キーワードによる切り替えは#ifdef ~ #endifで指定します。

マクロの改行

マクロの処理が複数行になる場合、改行したくなります。 以下のように記述するとコンパイルエラーです。

#define TEST_MACRO(abc) 
    abc.x = 0;

こちらのように\ (バックスラッシュ)をお尻に付けるとコンパイルが通ります。

#define TEST_MACRO(abc) \
    abc.x = 0;

記述要素が2種類以上ある場合は、こんな書き方も可能です。

#define TEST_MACRO(abc) {abc.x = 0; abc.y = 0;}

先と同じように改行したらコンパイルエラーになるので、先のように\をお尻に付けましょう。

#define Hoge(input) \
{\
    input.x = 0;\
    input.y = 0;\
}

C#側の処理

キーワードを動的に切り替えてシェーダを切り替える

if(m_enableMacro)
    mat.DisableKeyword("SHIBUYA24");
else
    mat.EnableKeyword("SHIBUYA24");

このようにEnableKeywordDisableKeywordメソッドを実行することで、MaterialのShaderを切り替えることが出来ます。

f:id:esakun:20170406224556g:plain

余談

#define TEST_MACRO(abc)

このように処理が何も記述されていないマクロを見かけますが、この場合は何も起きません。ご安心を。

まとめ

マルチコンパイルマクロを使えば、同じようなシェーダをいくつも作る必要がなくなり、ファイル構成をスッキリさせられます。

しかし、あまりこれらに頼るとコードの可読性が下がりそうで、何事もバランスが大事だなと思う次第でございます。

あわせてどうぞ

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info

www.shibuya24.info