材料实例 - MRTK2
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
行为中演示的示例用法。