【Unity】MaterialPropertyBlock を使ってマテリアルのインスタンスを増やさない

DEVELOP

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 とかは適切に割り当ててね。

Color に赤と緑を指定して実行してみた図

結果

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 が割り当てられたままになっていることを確認できます。

まとめ

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