マテリアル インスタンスの概要 — MRTK3

MaterialInstanceの挙動は、インスタンスマテリアルの有効期間の追跡を支援し、インスタンス化されたマテリアルをユーザーのために自動的に破棄します。 このユーティリティコンポーネントは、Renderer.materialまたはRenderer.materialsの代わりとして使用できます。

Note

MaterialPropertyBlocksは、マテリアルのインスタンス化よりも優先されますが、すべてのシナリオで常に利用できるとは限りません。

Renderer.materialの使用が問題になる可能性があるのはなぜでしょうか? 以下のコードをユニティシーンに追加して再生をヒットする場合、メモリ使用量が上昇し続けます。

public class Leak : MonoBehaviour
{
    private void Update()
    {
        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        // Memory leak, the material allocated is not tracked & destroyed.
        cube.GetComponent<Renderer>().material.color = Color.red;
        ...
        Destroy(cube);
    }
}

Note

実行に時間がかかりすぎる場合、上記のリーク挙動によってユニティがクラッシュします。

代替方法として、MaterialInstance挙動の使用を試します。

public class NoLeak : MonoBehaviour
{
    private void Update()
    {
        var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        // No memory leak, the material allocated is tracked & destroyed by MaterialInstance.
        cube.EnsureComponent<MaterialInstance>().Material.color = Color.red;
        ...
        Destroy(cube);
    }
}

使用

ユニティのRenderer.materialを呼び出すとき、ユニティは新しいマテリアルを自動的にインスタンス化します。 マテリアルが不要になったときや、ゲームオブジェクトが破棄されるときに、マテリアルを破棄するのは呼び出し元の責任です。 MaterialInstance挙動は、マテリアルリークの回避に役立ち、編集および実行中のマテリアル割り当てパスの一貫性を保持します。

MaterialPropertyBlockを使用できず、マテリアルをインスタンス化する必要がある場合、次のようにMaterialInstanceを使用できます。

public class MyBehaviour : MonoBehaviour
{
    // Assigned via the inspector.
    public Renderer targetRenderer;

    private void OnEnable()
    {
        Material material = targetRenderer.EnsureComponent<MaterialInstance>().Material;
        material.color = Color.red;
        ...
    }
}

複数のオブジェクトがマテリアルインスタンスの所有権を必要とする場合、参照追跡のために明示的な所有権を取得することをお勧めします。 (IMaterialInstanceOwner と呼ばれるオプションのインターフェイスが存在することにより、所有権に役立ちます。) 使用例を次に示します。

public class MyBehaviour : MonoBehaviour,  IMaterialInstanceOwner
{
    // Assigned via the inspector.
    public Renderer targetRenderer;

    private void OnEnable()
    {
        Material material = targetRenderer.EnsureComponent<MaterialInstance>().AcquireMaterial(this);
        material.color = Color.red;
        ...
    }

    private void OnDisable()
    {
        targetRenderer.GetComponent<MaterialInstance>()?.ReleaseMaterial(this)
    }

    public void OnMaterialChanged(MaterialInstance materialInstance)
    {
        // Optional method for when materials change outside of the MaterialInstance.
        ...
    }
}

詳細については、ClippingPrimitive挙動内で示される使用例を参照してください。

関連項目