Mesh中 material 和 sharedMaterial 的区别及内部实现的推断
2017-05-10 23:02
260 查看
material 和 sharedMaterial 的区别
创建一个Material, 颜色为红色,创建两个Quad,挂上刚刚创建的材质。 效果如下图:
将第一个Quad挂载如下脚本, 运行:
render = GetComponent<Renderer>(); render.material.color = Color.white;
效果如下图:
修改脚本内容如下, 运行:
render = GetComponent<Renderer>(); render.sharedMaterial.color = Color.white;
Quad的颜色变了
效果如下图:
如何来解释上面的现象呢, 根据官方文档
Renderer.sharedMaterial
sharedMaterial 是共用的 Material,称为共享材质。修改共享材质会改变所用使用该材质的物体,并且编辑器中的材质设置也会改变。
Renderer.material
material 是独立的 Material,返回分配给渲染器的第一个材质。修改材质仅会改变该物体的材质。如果该材质被其他的渲染器使用,将克隆该材质并用于当前的渲染器。
推测 sharedMaterial 和 material 的实现
下面我们通过一些实现猜测 material 是如何实现的:我们从 UnityEngine.Renderer 中可得知 sharedMaterial 和 material 是属性(property),当给属性赋值时会隐式的调用 set 方法,当获取属性值得时候会隐式的调用 get 方法。假设 sharedMaterial 的值变量假设为 _sharedMaterial, material 的值变量假设为 _material。
Material _material; Material _sharedMaterial;
第一个测试:
Material origin_sharedMat = render.sharedMaterial; Debug.Log(origin_sharedMat == render.sharedMaterial); // True
调用了 sharedMaterial 的 get方法。 可以推断出 sharedMaterial 的 get:
return _sharedMaterial;
第二个测试:
Material new_Mat = new Material(Shader.Find("Standard")); render.sharedMaterial = new_Mat; Debug.Log(new_Mat == render.sharedMaterial); // True
调用了 sharedMaterial 的 set方法。 可以推断出 sharedMaterial 的 set:
_sharedMaterial = value;
第三个测试:
Material origin_sharedMat = render.sharedMaterial; Material origin_Mat = render.material; Debug.Log(origin_sharedMat == render.sharedMaterial); Debug.Log(origin_Mat == render.sharedMaterial); Debug.Log(origin_Mat == render.material); // Flase True True
在隐式调用 material 的 get 后, sharedMaterial 被修改。且 _material 和 _sharedMaterial 相等。
推断 material 的 get:
if (_sharedMaterial ~= _material) { _material = new Material (_sharedMaterial);//这一步由第四个测试共同推出 _sharedMaterial = _material; } return _material;
第四个测试:
Material new_Mat = new Material(Shader.Find("Standard")); render.sharedMaterial = new_Mat; Debug.Log(new_Mat == render.sharedMaterial); Material origin_Mat = render.material; Debug.Log(new_Mat == origin_Mat); Debug.Log(origin_Mat == render.sharedMaterial); Debug.Log(origin_Mat == render.material); // True Flase True True
很明显 _material的初始化并未通过 material 属性,因为未调用 material 属性的 get 方法前,_sharedMaterial 和 _material并不相等。
推断 sharedMaterial 的 set:
_sharedMaterial = value;
第五个测试:
Material new_Mat = new Material(Shader.Find("Standard")); render.material = new_Mat; Debug.Log(new_Mat.name); Debug.Log(render.sharedMaterial.name); Debug.Log(render.material.name); // Standard Standard Standard(Instance)
推测 material 的 set:
_sharedMaterial = value;
综上推断:
public Material material { get { if (_sharedMaterial ~= _material) { _material = new Material (_sharedMaterial); _sharedMaterial = _material; } 4000 return _material; } set { _sharedMaterial = value; } } public Material sharedMaterial { get { return _sharedMaterial; } set { _sharedMaterial = value; } }
使用 material 时的内存泄漏问题
每一次引用 Renderer.material 的时候,都会生成一个新的 material 到内存中去,销毁物体的时候需要我们手动去销毁该material,否则会一直存在内存中。官方文档说:
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.
此方法自动实例化该材质并且使其成为该渲染器独有的材质。当该游戏物体被删除时,你应该手动删除该材质。当替换场景调用 Resources.UnloadUnusedAssets 也可以删除该材质。
网上的解决方案如下:
http://www.xuanyusong.com/archives/2530
编辑器下使用 material, 其他平台使用 sharedMaterial
public static Material GetMaterial(Renderer render) { #if UNITY_EDITOR return render.material; #else return render.sharedMaterial; #endif }
http://www.jianshu.com/p/ababf547d992
如果是主角这一类gameobject身上需要修改材质的属性或者shader属性比较多的时候,可以第一次使用material,这样可以动态的生成一个material实例,然后再使用sharedmaterial,动态的修改这个新生成的material,而且不会创建新的material。
https://blog.uwa4d.com/archives/optimzation_memory_2.html
一般情况下,资源属性的改变情况都是固定的,并非随机出现。比如,假设GameObject受到攻击时,其Material属性改变随攻击类型的不同而有三种不同的参数设置。那么,对于这种需求,我们建议你直接制作三种不同的Material,在Runtime情况下通过代码直接替换对应GameObject的Material,而非改变其Material的属性。这样,你会发现,成百上千的instance Material在内存中消失了,取而代之的,则是这三个不同的Material资源。
如有错误,欢迎指出。
email:dxmdxm1992#gmail.com
blog: csdn magicdavid.top
相关文章推荐
- mesh和sharedMesh的区别
- strcpy和memcpy的区别 与内部实现
- Servlet内部跳转和外部跳转的区别,底层实现原理
- java中HashMap,LinkedHashMap,TreeMap,HashTable,ConcurrentHashMap的区别和内部实现机制
- 几个问题(十六)-------Servlet内部跳转和外部跳转的区别,底层实现原理
- Oracle Join 内部实现区别
- 使用qt内部数值动画实现弹簧效果的探索及属性带有{}和没有{}的区别
- 内部跳转和外部跳转的区别,底层实现原理
- Unity MeshRender中material和sharedmaterial的区别
- 正确实现IDisposable Dispose和Close的区别
- 类中成员函数的实现,放在类块里和外部实现的区别
- UML中几种类间关系:继承、实现、依赖、关联、聚合、组合的联系与区别
- ucenter整合同步登录的内部实现原理
- PopupWindow的代码实现,以及和AlertDialog的区别
- java实现多线程的方式以及run方法和start方法的区别
- angularjs material 实现搜索框
- java重载与重写的区别+重写父类equals方法的完美实现
- getSharedPreferences 与 getPreferences 与getDefaultSharedPreferences的区别
- winform拖拽:实现外部文件拖拽到程序内以及程序内部间的拖拽
- 局部内部类的例子代码及实现最简单闹钟应用