Version: 2018.2
物理ベースのレンダリングマテリアルバリデーター
シェーダーを書く

マテリアルパラメーターへのスクリプトを使ったアクセスと変更

マテリアルのインスペクターに表示されているパラメーターはすべて、スクリプトからアクセスすることが可能なので、実行時にマテリアルを変化させたりアニメートさせたりすることができます。

これは、色の変化、ゲーム実行中の動的なテクスチャの差替えなど、マテリアルのさまざまな値の変更を可能とします。最も一般的に使われる機能は以下のとおりです。

機能名 用途
SetColor マテリアルの色を変える (例 Albedo カラー)
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つの問題があります。

1. 必要なスタンダードシェーダー バリアントの正しいキーワードを有効にする

スタンダードシェーダーの異なるバリアントを使うようにスクリプトからマテリアルを変更する場合、EnableKeyword 関数 を使って、バリアントを有効にしなくてはなりません** マテリアルで最初から使われていなかったシェーダー機能を使い始めると、異なるバリアントが要求されます。例えば、それまで無かった法線マップをマテリアルに適用したり、元々0だった Emissive level の値を0より大きくした場合などです。

スタンダードシェーダーの機能を有効にするための特定キーワードは以下のとおりです。

キーワード 機能
_NORMALMAP 法線マップ
_ALPHATEST_ON 透明度の “Cut out” レンダリングモード
_ALPHABLEND_ON 透明度の “Fade” レンダリングモード
_ALPHAPREMULTIPLY_ON 透明度の “Transparent” レンダリングモード
_EMISSION 放出色 または 放出マップ
_PARALLAXMAP ハイトマップ
_DETAIL_MULX2 補助的 “詳細” マップ (アルベド&法線マップ)
_METALLICGLOSSMAP メタリックワークフローの メタリック/スムースネスマップ
_SPECGLOSSMAP スペキュラーワークフローの スペキュラー/スムースネスマップ

上記のキーワードによるスクリプトからのマテリアルの変更は、エディター上で実行中でも問題無く行う事ができます。

ですが、ビルドに含むバリアントを割り出すために Unity がチェックするのは、プロジェクトで使われているマテリアルだけなので、実行中にスクリプトから一時的に変更した だけ のバリアントは含まれません。

これは、例えばスクリプトからマテリアルの _PARALLAXMAP キーワードを有効にしているのに、プロジェクト内に一致する機能の組合せを持つマテリアルが無かった場合、視差マッピングは、たとえエディター上では機能しているように見えたとしても、最終的なビルドでは有効にならない、という事です。なぜなら、バリアントが要求されたように見えず、ビルドから省かれてしまうからです。

2. Unity に必要なシェーダーバリアントがあることを確認する

このため、そのタイプのマテリアルを少なくとも一つ、アセットに用意して、 Unity にそのシェーダーバリアントを使う事を明示する必要があります。そのマテリアルは シーンで使われていなくてはなりません 。もしくは、 ランタイム時にリソースを読み込んで おくという方法もあります。そうしないと Unity からは、まだ使っていないように見えるため、ビルドから除外されてしまいます。

上記の手順を済ませておけば、実行中にスタンダードシェーダーを使っているマテリアルを思い通りに変更することが可能になります。

シェーダーバリアントの詳細について興味があり、自分で書く場合はどうしたらよいか知りたいのであれば、 複数のシェーダープログラムのバリアントを作る を読んでください。

物理ベースのレンダリングマテリアルバリデーター
シェーダーを書く