material和sharedMaterial

unity中material的使用,在每次set(即rederMesh.material或者rederMesh.sharedMaterial赋值)之后使用renderMesh.material get时内存中都会new出一个新的material的实例对象,然而renderMesh.sharedMaterial get时不会实例新的对象,会指向set之后的实例对象(如果没有set直接获取到的是asset下面的material)。也就是说如果用rederMesh.sharedMaterial来更新材质属性,那么所有用到这个材质的物体都会发生变化,如果用rederMesh.material,那么只有当前这个物体会发生变化。
举例说明:
1.material先get

var renderer = GetComponent();

var mat = renderer.material;
var sharedMat = renderer.sharedMaterial;

Debug.Log(mat);
Debug.Log(sharedMat );
Debug.Log(mat==shardeMat);

//输出结果:mat (Instance),mat (Instance) ,True
2.sharedMaterial先get
var renderer = GetComponent();
//对比1的顺序变化
var sharedMat = renderer.sharedMaterial;
var mat = renderer.material;

Debug.Log(mat);
Debug.Log(sharedMat );
Debug.Log(mat==sharedMat );
//输出结果:mat (Instance),mat ,False,sharedMat Get到的是最原始的matrial(asset下面的)

material和sharedMaterial的代码实现原理如下:
material属性的get:第一次调用会改变renderer里的材质,然后取值。这里第一次的定义是,实际意义上的第一次,以及每次调用过material或sharedMaterial的Set属性以后的第一次。
material属性的set:单纯的给renderer里的材质赋值。
sharedMaterial属性的get:单纯的取值
sharedMaterial属性的set:单纯的赋值
public class Renderer {

Material realMaterial;

bool firstGet=true;

Material material
{
    get
    {
        if(firstGet)
        {
            realMaterial = Object.Instantiate(realMaterial);
            firstGet = false;
        }
        return realMaterial;
    }
    set
    {
        firstGet = true;
        realMaterial = value;
    }
}

Material sharedMaterial
{
    get
    {
        return realMaterial;
    }
    set
    {
        firstGet = true;
        realMaterial = value;
    }
}

}

3关于maerials
Renderer.materials
先上API https://docs.unity3d.com/ScriptReference/Renderer-materials.html

返回的是所有实例化的材质。Unity支持一个Renderer包含多个材质,所以这个属性会返回一个包含该Renderer所有材质的数组。如果不止一个材质,sharedMaterial 和 material属性会返回第一个使用的材质。
使用该属性时,Renderer的所有材质都经过了一次实例化,所以改变材质球只会影响到该物体。和material一样的原理
注意:就像Unity返回的所有数组一样,返回的是一个经过复制的数组副本,如果要改变数组中的某些材质,需要重新赋值一个数组给Renderer。 这些实例化的材质也需要手动销毁或者加载新场景的时候自动回收。

举例如下:
直接改变材质数组中某个材质的属性是可以的。

//成功变成黑色
GetComponent().materials[0].color = Color.black;
//成功删除贴图
GetComponent().materials[0].SetTexture("_MainTex", null);
//成功改变shader
GetComponent().materials[0].shader = Shader.Find(“Standard”);
但是想要更换某个材质球就不行了

//材质数组中的材质没有发生改变
GetComponent().materials[0] = new Material(Shader.Find(“Standard”));
正确的赋值方式如下

Material[] matBuff = GetComponent().materials;
matBuff[0] = new Material(Shader.Find(“Standard”));//到这一步还不行
GetComponent().materials = matBuff;//必须要赋值回去

//接着测试一下set方法接收的数组是不是副本
matBuff[0] = null;//到这里还不起作用 是副本
GetComponent().materials = matBuff;//还是要赋值回去
所以,Unity返回的是一个新建的数组,然后旧数组的元素逐个赋值给新数组的元素,新旧数组元素的引用都指向同一个材质球,但新数组的元素引用一旦发生改变,旧数组不会受到影响。

另外,可以注意到调用过Renderer.materials属性之后,materials中材质的索引顺序和物体身上显示的材质球顺序是相反的。

UI.Graphic.material
当我们需要在UGUI上使用自定义材质并在运行时改变它时,就要用到material属性,这个属性相当于Renderer.sharedMaterial,返回的是共享材质(default ui material ),当我们希望它只影响一个UI时,就要自己实例化一个材质并赋值给UI。

Material mat = GetComponent().material;
mat = Instantiate(mat);
GetComponent().material = mat;
之后再进行修改材质的属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值