材质实例 Material instance
MaterialInstance
behavior有助于跟踪材质实例的生命周期,并自动销毁用户的材质实例。这个实用组件可以用来替代Renderer.material 或
Renderer.materials.
Note
MaterialPropertyBlocks 比材质实例更受欢迎,但并非在所有场景中都可用。
为什么使用 Renderer.material 会成为一个问题?如果你把下面的代码添加到一个Unity场景,并点击播放内存使用将继续攀升和攀升:
public class Leak : MonoBehaviour
{
private void Update()
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
// 内存泄漏,分配的材质没有被跟踪和销毁。
cube.GetComponent<Renderer>().material.color = Color.red;
...
Destroy(cube);
}
}
Note
上述泄漏行为将崩溃Unity如果运行太久!
另一种方法是尝试使用MaterialInstance
behavior:
public class NoLeak : MonoBehaviour
{
private void Update()
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
// 没有内存泄漏,所分配的材质由MaterialInstance进行跟踪和销毁。
cube.EnsureComponent<MaterialInstance>().Material.color = Color.red;
...
Destroy(cube);
}
}
使用
当调用Unity的Renderer.material(s), Unity y会自动实例化新材质。当不再需要材质或游戏对象被销毁时,调用方有责任销毁材质。 MaterialInstance
有助于避免材质泄漏,并在编辑和运行时保持材质分配路径一致。
当一个 MaterialPropertyBlock 不能被使用,并且一个材质必须被实例化,MaterialInstance
可以被使用如下:
public class MyBehaviour : MonoBehaviour
{
// 在inspector上指派
public Renderer targetRenderer;
private void OnEnable()
{
Material material = targetRenderer.EnsureComponent<MaterialInstance>().Material;
material.color = Color.red;
...
}
}
如果多个对象需要材质实例的所有权,最好采用显式的所有权进行引用跟踪。(一个可选的接口叫做
IMaterialInstanceOwner
来辅助所有权。.) 下面是示例用法:
public class MyBehaviour : MonoBehaviour, IMaterialInstanceOwner
{
// 在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)
{
// 可选方法,当材质在 MaterialInstance外部发生变化时使用。
...
}
}
有关更多信息,请参见ClippingPrimitive
behavior中演示的示例用法.