Dela via


Översikt över materialinstans – MRTK3

Beteendet MaterialInstance hjälper till att spåra materiallivslängden för instanser och förstör automatiskt instansmaterial för användaren. Den här verktygskomponenten kan användas som ersättning för Renderer.material eller Renderer.materials.

Anteckning

MaterialPropertyBlocks föredras framför material-instancing men är inte alltid tillgängliga i alla scenarier.

Varför kan det vara ett problem att använda Renderer.material ? Om du lägger till koden nedan i en Unity-scen och använder uppspelningsminnet fortsätter du att klättra och klättra:

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

Anteckning

Ovanstående läckagebeteende kraschar Unity om det körs för länge!

Alternativt kan du prova att använda beteendet 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);
    }
}

Användning

När Unitys Renderer.material anropas instansierar Unity automatiskt nya material. Det är uppringarens ansvar att förstöra materialet när ett material inte längre behövs eller spelobjektet förstörs. Beteendet MaterialInstance hjälper till att undvika materialläckor och håller materialallokeringsvägarna konsekventa under redigerings- och körningstiden.

När en MaterialPropertyBlock inte kan användas och ett material måste instanseras, MaterialInstance kan användas på följande sätt:

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

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

Om flera objekt behöver ägarskap för den materiella instansen är det bäst att ta explicit ägarskap för referensspårning. (Det finns ett valfritt gränssnitt som heter IMaterialInstanceOwner för att hjälpa till med ägarskap.) Nedan visas exempelanvändning:

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

Mer information finns i exempelanvändningen som visas i ClippingPrimitive beteendet.

Se även