マテリアルのインスペクターに表示されているパラメーターはすべて、スクリプトからアクセスすることが可能なので、実行時にマテリアルを変化させたりアニメートさせたりすることができます。
これは、色の変化、ゲーム実行中の動的なテクスチャの差替えなど、マテリアルのさまざまな値の変更を可能とします。最も一般的に使われる機能は以下のとおりです。
機能名 | 用途 |
---|---|
SetColor | マテリアルの色を変えます (例えば、アルベド色) |
SetFloat | 浮動小数点の値を設定します (例えば、法線マップ乗数) |
SetInt | マテリアルに整数値を設定します |
SetTexture | マテリアルに新しいテクスチャを指定します |
スクリプトからマテリアルを操作するときに使える全機能が Material class scripting reference で参照できます。
一つ注意が必要なのは、これらの機能はマテリアルの ** 現在のシェーダーにのみプロパティが設定される ** という事です。これは、テクスチャを使っていないシェーダーや、何も反射しないシェーダーでは、 SetTexture を呼び出しても何も起きない、という事です。このため、何かプロパティを設定する前にシェーダーをセットした方がよいです。同じテクスチャやプロパティ項目を使っているシェーダーに切り替えた場合、それらの値は維持されます。
これらの機能は、レガシーシェーダーや、 スタンダードシェーダー 以外の 組込みシェーダー(例えば、 particle, sprite, UI それに unlit などのシェーダー)のような、すべての シンプルな シェーダーで動きます。 スタンダードシェーダー で使われるマテリアルでは、完全にマテリアルを変更するためには、さらに条件がある事を確認してください。
スタンダードシェーダーで実行時にマテリアルを変更したい場合、いくらかさらに条件があります。なぜなら、内部的に、沢山のさまざまなシェーダーが一つにまとめられているためです。
これらのさまざまなタイプのシェーダーは 複数のシェーダープログラムのバリアントを作る と呼ばれ、可能なシェーダー機能の全組み合わせと同等、と考える事ができます。組み合わせは、アクティブ・非アクティブの切り替えによって変える事ができます。
例えば、 法線マップ(Normal Map)(Bump mapping) をマテリアルに適用したい場合は、 Normal Mapping をサポートしているシェーダーの variant をアクティブにします。さらに Heightmap も適用したいのであれば、 Normal Mapping と Height Mapping をサポートしているシェーダーの variant をアクティブにします。
マテリアルでスタンダードシェーダーを使うけれど法線マップは使わない、という場合、さまざまなシェーダーコードを無効化して実行できる事から、法線マップシェーダーのコードを実行するコストを含めなくてよいので、これは優れた仕組みです。またこれは、何か機能の組合せ(例えばハイトマップとエミッシヴを一緒に使うなど)を行う必要がないという事でもあり、それらバリエーションは、ビルド時に完全に無効化できます。そして、実際、一般的にはスタンダードシェーダーで可能な少数のバリエーションを使うだけで済みます。
Unity は、使用可能なすべてのシェーダーバリアントを、そのままビルドには含めません。なぜなら、すべてを含めると膨大な数、数万単位になるためです。この膨大な数は、マテリアルインスペクターで設定可能な機能の組合せ結果によるものだけではなく、HDR、ライトマップ、GI、フォグなどのような他のレンダリング手法の機能を合わせて使うかどうかも関係してきます。すべてを含めた場合、読み込みが遅くなり、メモリ消費量が増大し、ビルドサイズとビルド時間も増える結果となります。
そうならないように、Unity はプロジェクトで使われているマテリアルアセットを調査して、どのバリアントが使われているかを追跡します。プロジェクトに含まれたスタンダードシェーダーのバリアントは、ビルドにも含まれることになります。
スタンダードシェーダーの使用で、スクリプトからマテリアルにアクセスするときに2つの問題があります。
スタンダードシェーダーの異なるバリアントを使うようにスクリプトからマテリアルを変更する場合、EnableKeyword 関数 を使って、バリアントを有効にしなくてはなりません** マテリアルで最初から使われていなかったシェーダー機能を使い始めると、異なるバリアントが要求されます。例えば、それまで無かった法線マップをマテリアルに適用したり、元々0だった Emissive level の値を0より大きくした場合などです。
スタンダードシェーダーの機能を有効にするための特定キーワードは以下のとおりです。
キーワード | 機能 |
---|---|
_NORMALMAP | 法線マップ |
_ALPHATEST_ON | 透明度の “Cut out” レンダリングモード |
_ALPHABLEND_ON | 透明度の “Fade” レンダリングモード |
_ALPHAPREMULTIPLY_ON | 透明度の “Transparent” レンダリングモード |
_EMISSION | 放出色 または 放出マップ |
_PARALLAXMAP | ハイトマップ |
_DETAIL_MULX2 | 補助的 “詳細” マップ (アルベド&法線マップ) |
_METALLICGLOSSMAP | メタリックワークフローの メタリック/スムースネスマップ |
_SPECGLOSSMAP | スペキュラーワークフローの スペキュラー/スムースネスマップ |
上記のキーワードによるスクリプトからのマテリアルの変更は、エディター上で実行中でも問題無く行う事ができます。
ですが、ビルドに含むバリアントを割り出すために Unity がチェックするのは、プロジェクトで使われているマテリアルだけなので、実行中にスクリプトから一時的に変更した だけ のバリアントは含まれません。
これは、例えばスクリプトからマテリアルの _PARALLAXMAP キーワードを有効にしているのに、プロジェクト内に一致する機能の組合せを持つマテリアルが無かった場合、視差マッピングは、たとえエディター上では機能しているように見えたとしても、最終的なビルドでは有効にならない、という事です。なぜなら、バリアントが要求されたように見えず、ビルドから省かれてしまうからです。
このため、そのタイプのマテリアルを少なくとも一つ、アセットに用意して、 Unity にそのシェーダーバリアントを使う事を明示する必要があります。そのマテリアルは シーンで使われていなくてはなりません 。もしくは、 ランタイム時にリソースを読み込んで おくという方法もあります。そうしないと Unity からは、まだ使っていないように見えるため、ビルドから除外されてしまいます。
上記の手順を済ませておけば、実行中にスタンダードシェーダーを使っているマテリアルを思い通りに変更することが可能になります。
シェーダーバリアントの詳細について興味があり、自分で書く場合はどうしたらよいか知りたいのであれば、 複数のシェーダープログラムのバリアントを作る を読んでください。