Materialinstans

Beteendet MaterialInstance ger vid spårning av instansens materiallivslängd och förstör automatiskt användargränssnittsmaterial 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 materialankare, 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 nedanstående kod till en Unity-scen och använder uppspelningsminne fortsätter du att gå upp och hoppa:

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äckbeteende kraschar Unity om det har körts för länge!

Alternativt kan du prova att använda MaterialInstance beteendet:

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 Unity anropar Renderer.material instansierarUnity automatiskt nya material. Det är anroparens ansvar att förstöra material när ett material inte längre behövs eller om spelobjektet förstörs. Beteendet MaterialInstance hjälper till att undvika materialläckage och ser till att materialallokeringsvägarna är konsekventa under redigering och körning.

När en MaterialPropertyBlock inte kan användas och ett material måste instanseras kan MaterialInstance 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 materialinstansen är det bäst att ta explicit ägarskap för referensspårning. (Ett valfritt gränssnitt som IMaterialInstanceOwner kallas finns för att underlätta ägarskapet.) Nedan visas exempel på anvä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