温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的

发布时间:2021-11-15 16:44:34 来源:亿速云 阅读:608 作者:柒染 栏目:大数据

本篇文章为大家展示了Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

material 和 sharedMaterial 的区别

创建一个Material, 颜色为红色,
创建两个Quad,挂上刚刚创建的材质。 效果如下图:

Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的

将第一个Quad挂载如下脚本, 运行:

render = GetComponent<Renderer>();render.material.color = Color.white;

效果如下图:

Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的

修改脚本内容如下, 运行:

render = GetComponent<Renderer>();render.sharedMaterial.color = Color.white;

Quad的颜色变了
效果如下图:

Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的

如何来解释上面的现象呢, 根据官方文档

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;
  • 1

  • 第二个测试:

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;

        }        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 也可以删除该材质。


编辑器下使用 material, 其他平台使用 sharedMaterial

public static Material GetMaterial(Renderer render)  
    {  #if UNITY_EDITOR  
        return render.material;  #else  
        return render.sharedMaterial;  #endif  
    }

如果是主角这一类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资源。

上述内容就是Unity3D Mesh中material和sharedMaterial的区别及内部实现的推断是怎样的,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI