sharedMaterial和material的区别

区别点

  1. sharedMaterial表示共享材质,修改共享材质会改变所有使用该材质的物体,并且编辑器中的材质设置也会变

  2. material表示材质实例,修改材质仅会改变物体的材质,如果该材质被其他渲染器使用,将克隆该材质用于当前的渲染器

  3. 每次引用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;
        }
    }
}

实际运用注意点(优化点)

  1. material字段会产生新的资源,要注意销毁

  2. 改变sharedMaterial不会产生内存消耗,但是会把内存中原始的Material资源更改掉

  3. //我们需要改变共享材质,但是在编辑器模式下 我们不想原始资源频繁被改动 可以这样子
    public static Material GetMaterial(Renderer render)  
        {  
    #if UNITY_EDITOR  
            return render.material;  
    #else  
            return render.sharedMaterial;  
    #endif  
        }  
  4. 如果是主角这一类gameobject身上需要修改材质的属性或者shader属性比较多的时候,可以第一次使用material,这样可以动态的生成一个material实例,然后再使用sharedmaterial,动态的修改这个新生成的material,而且不会创建新的material

  5. 一般情况下,资源属性的改变情况都是固定的,并非随机出现。比如,假设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 的区别及内部实现的推断 (看了源码,作者推断的是正确的)

赋值新材质无效问题记录

Unity里面获取Material里面的所有Texture

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值