MaterialPropertyBlockの使い方です。
Unity2018.3.1f1
MaterialPropertyBlock?
いま、こんな感じで色を変更できるシェーダがMaterialに設定されているとします。
そしてこのMaterialを使うGameObjectが二つあります。
ここでそれぞれのオブジェクトの色を別の色に変えたいとすると、
Materialをもう一個作って別々のMaterialをアサインしなければいけません。
二つくらいだったらいいのですが、このような色違いのGameObjectが100個あるケースを考えると、
少しプロパティを変更するだけでMaterialを100個インスタンス化するのは効率が悪そうです。
こんな時にMaterialPropertyBlockを使えば、Materialのインスタンスは変えずに一部のプロパティだけ変更できます。
シェーダを書く
検証のためにプロパティで色を変えられるシェーダを書きます。
Shader "Example" { Properties{ _Color ("Color", Color) = (1,1,1,1) } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float4 _Color; float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { return _Color; } ENDCG } } }
シンプルなので特に説明は必要ないかと思います。
普通にInspectorから色を設定できます。
スクリプトから色を変える
次にスクリプトからMaterialPropertyBlockを使って色を変更します。
using UnityEngine; public class Example : MonoBehaviour { [SerializeField] private Color _color; private MeshRenderer _renderer; private MaterialPropertyBlock _materialPropertyBlock; private void Start() { _renderer = GetComponent<MeshRenderer>(); _materialPropertyBlock = new MaterialPropertyBlock(); } private void Update() { // この時点ですでにほかのスクリプトなどからMaterialPropertyBlockが // セットされているかもしれないので、まずは取得する _renderer.GetPropertyBlock(_materialPropertyBlock); // MaterialPropertyBlockに対して色をセットする _materialPropertyBlock.SetColor("_Color", _color); // MaterialPropertyBlockをセットする _renderer.SetPropertyBlock(_materialPropertyBlock); } }
説明はコメントに書いた通りです。
MaterialPropertyBlockを使うと、MateiralのInspectorから指定した色は無視され、
MaterialPropertyBlockで設定した色で上書きされます。
結果
このスクリプトをそれぞれのGameObjectにアタッチして再生、色を変えてみます。
Materialのインスタンスは同一のまま、色を変更することができました。
プロパティは定義しなくてもいい
MateiralPropertyBlockでプロパティを変更する場合はシェーダのPropetiesを書く必要はないので消してもOKです。
Shader "Example" { // Propetiesは消した SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" // これは必要 float4 _Color; float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); } fixed4 frag () : SV_Target { return _Color; } ENDCG } } }
ドローコールとかが減るわけじゃない
下記の記事にも書きましたが、MaterialPropertyBlockを使ったからと言ってDraw CallやSetPass Callの削減には繋がりません。
あくまでMaterialのインスタンスを無駄に増やさなくて済む機能になります。