Общие сведения об экземпляре материала — MRTK3

Поведение MaterialInstance помогает отслеживать время существования материала экземпляра и автоматически уничтожает экземплярные материалы для пользователя. Этот компонент служебной программы можно использовать в качестве замены Renderer.material или Renderer.materials.

Примечание

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

Если нескольким объектам требуется владение экземпляром материала, лучше применить явное владение для отслеживания ссылок. (Дополнительный интерфейс, называемый 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.

См. также раздел