天天看点

Unity中Renderer.material的坑

unity中renderer的可以用material和sharedMaterial来访问材质,多个renderer可以公用一个材质,这时sharedMaterial指向同一个材质,修改这个材质后所有renderer都会有所变化。至于用material来访问,按官方文档说法是:

Modifying 

material

 will change the material for this object only.

修改material只会改变当前物体

If the material is used by any other renderers, this will clone the shared material and start using it from now on.

如果材质还被其它renderer使用,会克隆共享的材质

Note:

This function automatically instantiates the materials and makes them unique to this renderer. It is your responsibility to destroy the materials when the game object is being destroyed. Resources.UnloadUnusedAssets also destroys the materials but it is usually only called when loading a new level.

这个函数会自动实例化材质,以便renderer独享该材质实例。需要在对象删除时手动销毁材质。 Resources.UnloadUnusedAssets也可以销毁该材质,但通常只会在加载新关卡时。

如果程序中写了如下示例代码:

public class Test : MonoBehaviour

{

           Material newMaterial;

           void CreateMaterial()

          {

               newMaterial = Instantiate(Resources.Load<Material>("PanoSphereImage"));

               renderer.material = newMaterial;

          }

         void ModifyMaterial1()

          {

               newMaterial.SetFloat("Factor", 1.0);

          }

         void ModifyMaterial2()

          {

               renderer.material.SetFloat("Factor", 2.0);

          }

}

按照通常的理解

renderer.material = newMaterial;

执行后,renderer.material 和 newMaterial 应该指向同一个对象,所以访问 renderer.material 和 newMaterial 是访问同一个对象。

在 renderer.material = newMaterial; 语句执行后renderer.material 和 newMaterial确实是指向同一个对象,这时执行函数 ModifyMaterial1(),物体的效果会改变,再执行 ModifyMaterial2(),物体效果也会改变,

但是坑来了,renderer.material.SetFloat("Factor", 2.0); 语句访问了 renderer.material,导致renderer克隆并使用了一个新的材质实例,所以renderer的material和sharedMaterial指向的材质对象与newMaterial指向的材质对象

已经不同了,如果再执行ModifyMaterial1(),物体并不会变化。

即使不对renderer.material进行修改,仅仅是访问,比如

string name = renderer.material.name; 

Material mat = renderer.material; 

也会导致renderer会克隆一个新实例出来。

在上述代码中,newMaterial并没有被其它renderer使用,但还是出现了克隆。

不过也并不是每次访问 renderer.material 都会导致克隆操作,后续通过 renderer.material 进行访问或设置都是指向同一个对象。

继续阅读