Unity では Material の色を変えたりUVを変更したりした時点で Material のインスタンスが複製されてしまいます。値の変更だけなのに…そんなMaterial インスタンスの複製を防ぐためのものが MaterialPropertyBlock です。 留意点として MaterialPropertyBlock を利用しても Draw Call は減りません。 勘違いしている人をちらほら見ます。
確認環境
2019.3.06f
サンプルコード( MaterialPropertyBlock 未使用)
まずは MaterialPropertyBlock を使わずにサンプルコードを書いてみます。
using UnityEngine;
public class Sample : MonoBehaviour
{
[SerializeField, Header("適用する色")]
private Color m_color;
public Color color
{
get { return m_color; }
}
[SerializeField, Header("メッシュレンダラー")]
private MeshRenderer m_meshRenderer;
public MeshRenderer meshRenderer
{
get { return m_meshRenderer; }
}
/// <summary>
/// 開始
/// </summary>
void Start()
{
if (meshRenderer != null)
{
meshRenderer.material.SetColor(Shader.PropertyToID("_Color"), color);
}
}
}
これをUnity デフォルトのSphere にでも AddComponentして実行してみます。meshRenderer とかは適切に割り当ててね。

結果
Mesh の マテリアル項目に(Instance) の表記があると複製されています。

サンプルコード( MaterialPropertyBlock 使用時)
using UnityEngine;
public class Sample : MonoBehaviour
{
[SerializeField, Header("適用する色")]
private Color m_color;
public Color color
{
get { return m_color; }
}
[SerializeField, Header("メッシュレンダラー")]
private MeshRenderer m_meshRenderer;
public MeshRenderer meshRenderer
{
get { return m_meshRenderer; }
}
/// 追加!!!
private MaterialPropertyBlock m_mpb;
public MaterialPropertyBlock mpb
{
get { return m_mpb ?? (m_mpb = new MaterialPropertyBlock()); }
}
/// <summary>
/// 開始
/// </summary>
void Start()
{
if (meshRenderer != null)
{
mpb.SetColor(Shader.PropertyToID("_Color"), color);
meshRenderer.SetPropertyBlock(m_mpb);
}
}
}
結果
Material のインスタンスが複製されずにオリジナルのMaterial が割り当てられたままになっていることを確認できます。

まとめ
小さな最適化かもしれませんが、塵も積もれば山となる。丁寧に作っていきたいですね。