sharedMaterial和material的区别
Posted 僵师先森
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sharedMaterial和material的区别相关的知识,希望对你有一定的参考价值。
区别点
-
sharedMaterial表示共享材质,修改共享材质会改变所有使用该材质的物体,并且编辑器中的材质设置也会变
-
material表示材质实例,修改材质仅会改变物体的材质,如果该材质被其他渲染器使用,将克隆该材质用于当前的渲染器
-
每次引用Renderer.material的时候,会生成一个新的material在内存当中,需要注意内存泄漏。销毁物体的时候需要手动销毁material(Destroy(material)),或者在切换场景的时候调用Resources.UnloadUnusedAssets也可以删除该材质。
实例化出的Material无法使用Resources.UnloadAsset()销毁,因为Resource.UnloadAsset是卸载asset资源,实例化出的Material需要通过Destory来销毁。
4.调用Renderer.sharedMaterials 相同的两个材质球 ,返回的也是两个,如下图,
源码解析
源码说明
Renderer会有一个m_Materials数组,Instantiate的GameObject的Renderer组件中m_Materials引用了materials依赖资源
sharedMaterials属性的get是拿到m_Materials,sharedMaterials属性的get是传入参数0 拿到m_Materials[0] 第一个材质
materials属性的get是会Instantiate一份m_Materials出来,并且将m_Materials = (Instantiate)m_Materials,material属性的get是拿到的是重新赋值后的m_Materials[0]
伪代码
class Renderer Material[] m_Materials; //GameObject Instantiate出来之后 他是引用了依赖的Material Material[] sharedMaterials get return m_Materials; set m_Materials = value; Material sharedMaterial get return m_Materials[0]; set m_Materials[0] = value; Materials[] materials get Material[] instMats = new Material[m_Materials.length]; for(int i=0;i<m_Materials.Length;i++) Material newMat = 实例化m_Material[i]出来 instMats[i] = newMat; m_Materials[i] = newMat; //注意后面sharedMaterials拿的是重新赋值后的 return instMats; set m_Materials[0] = value; Material material get Material instMat = 实例化m_Material[0]出来 m_Materials[0] = instMat; //注意后面sharedMaterial拿的是重新赋值后的 return instMat; set m_Materials[0] = value;
实际运用注意点(优化点)
-
material字段会产生新的资源,要注意销毁
-
改变sharedMaterial不会产生内存消耗,但是会把内存中原始的Material资源更改掉
-
//我们需要改变共享材质,但是在编辑器模式下 我们不想原始资源频繁被改动 可以这样子 public static Material GetMaterial(Renderer render) #if UNITY_EDITOR return render.material; #else return render.sharedMaterial; #endif
-
如果是主角这一类gameobject身上需要修改材质的属性或者shader属性比较多的时候,可以第一次使用material,这样可以动态的生成一个material实例,然后再使用sharedmaterial,动态的修改这个新生成的material,而且不会创建新的material
-
一般情况下,资源属性的改变情况都是固定的,并非随机出现。比如,假设GameObject受到攻击时,其Material属性改变随攻击类型的不同而有三种不同的参数设置。那么,对于这种需求,我们建议你直接制作三种不同的Material,在Runtime情况下通过代码直接替换对应GameObject的Material,而非改变其Material的属性。
但是注意动态替换Material sharedMaterials[0] = 某个材质 是不生效的 正确使用如下
Renderer psr = gameObject.GetComponent<Renderer>(); psr.sharedMaterials[0] = newMat //错误 不会生效 //正确赋值 Material[] arrMat = psr.sharedMaterials; arrMat[0] = newMat; psr.sharedMaterials = arrMat; //单独赋值material也是生效的 psr.sharedMaterial = newMat //解析: //sharedMaterials的get方法返回的引用是const修饰的常引用,可能这个造成了无法修改 或者是sharedMaterials的get方法返回的一份拷贝的材质数组 //sharedMaterial拿到的是m_Materials数组的第一个元素 //二者set的方法都是对数组进行重新赋值
参考链接
Mesh中 material 和 sharedMaterial 的区别及内部实现的推断 (看了源码,作者推断的是正确的)
关于material和sharedMaterial的问题
在unity3d中,Renderer组件有两个属性:material和sharedMaterial,它们都可以用来获取Renderer的材质属性。但是它们之间却又很大的区别,下面通过示例来讲解一下。
准备工作:unity3d中新建一个空场景;创建两个cube,分别命名为Cube0、Cube1;在Project中新建一个材质球,取名M0,shader选择Unlit/Color,shader的Main Color属性设为白色,即(255,255,255,255);将M0分别赋值给Cube0、Cube1;新建一个脚本TestMaterial,将脚本拖到Cube0上。如下所示:
1、测试material
TestMaterial脚本的内容如下所示:
1 using UnityEngine; 2 using System.Collections; 3 4 public class TestMaterial : MonoBehaviour 5 { 6 Renderer thisRenderer; 7 // Use this for initialization 8 void Start() 9 { 10 thisRenderer = GetComponent<Renderer>(); 11 thisRenderer.material.color = Color.red; 12 } 13 }
运行,效果如下图所示:
注意,只有Cube0的颜色改变,在mesh renderer中,材质球的名字是M0(Instance)。
2、测试sharedMaterial
代码如下:
1 using UnityEngine; 2 using System.Collections; 3 4 public class TestMaterial : MonoBehaviour 5 { 6 Renderer thisRenderer; 7 // Use this for initialization 8 void Start() 9 { 10 thisRenderer = GetComponent<Renderer>(); 11 thisRenderer.sharedMaterial.color = Color.red; 12 } 13 }
运行,效果如下所示:
注意,Cube0、Cube1的颜色均发生改变,但是在mesh renderer中,材质球的名字还是M0。但是,此时在Project中的M0的Main Color属性发生了改变,如下所示:
总结:使用material属性的时候,每次都会new一份新的material作用与它,但不会改变本地工程中的材质material;sharedMaterial是共享材质,无论使用多少次,内存中都只会占用一份内存,但是会影响其他使用同一材质球的对象。所以,从效率上来说,sharedMaterial的效率更高。
重点来了:在实际使用的时候,我们可以在开始的时候使用material产生一个新的材质球作用于该renderer,然后之后的操作都使用sharedMaterial,这样,效率更高,而且不会影响其他使用同一个材质球的renderer。
最后,附上示例代码:
1 using UnityEngine; 2 using System.Collections; 3 4 public class TestMaterial : MonoBehaviour 5 { 6 Renderer thisRenderer; 7 float delay = 3f; 8 float changeColorTm; 9 bool isChangeOnce; 10 11 void Awake() 12 { 13 thisRenderer = GetComponent<Renderer>(); 14 thisRenderer.material.color = Color.red; 15 changeColorTm = Time.time + delay; 16 isChangeOnce = false; 17 } 18 19 void Update() 20 { 21 if (!isChangeOnce && Time.time >= changeColorTm) 22 { 23 isChangeOnce = true; 24 thisRenderer.sharedMaterial.color = Color.green; 25 } 26 } 27 }
以上是关于sharedMaterial和material的区别的主要内容,如果未能解决你的问题,请参考以下文章
Unity --- sharedMaterial material
Unity_Renderer 中(sharedMaterial 和Miaterial)