材料实例

MaterialInstance 行为有助于跟踪实例材料生存期,并自动销毁用户的实例材料。 此实用工具组件可用于替换 Renderer.materialRenderer.material

备注

MaterialPropertyBlocks 比材料实例化更可取,但并非在所有方案中始终可用。

为什么使用 Renderer.material 是一个问题? 如果将以下代码添加到 Unity 场景并点击播放内存使用量将继续增加和减少:

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);
    }
}

备注

如果运行时间 过长,上述 泄漏行为将崩溃 Unity!

作为替代方法,请尝试使用 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);
    }
}

使用情况

在调用 Unity 的 Renderer.material (时) Unity 会自动实例化新的材料。 当不再需要材料或游戏对象被销毁时,调用方负责销毁材料。 该 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;
        ...
    }
}

如果多个对象需要材料实例的所有权,则最好使用显式所有权进行引用跟踪。 (ownership 的 aide 存在名为 的可选接口 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 用法。

另请参阅