【unity】材质修改使用实例

Material

Set
  • render.material
    会实例化一份材质
    runtime 允许多怪
    API render.material.Get/SetXXX
  • shareMaterial
    会全都改
    非运行时不能创建.material
    API render.shareMaterial.Get/SetXXX
  • MaterialPropertyBlock
    直接set,多MPB之间独立,但Keyword依然从material设置,MPB本来就可以每个不一样,但是keyword不可以
    降低内存使用
    Editor使用此接口将使面板不可修改
Get
var renderers = gameObject.GetComponentsInChildren<Renderer>();
var _propID = Shader.PropertyToID("_Color");
var mpbs = new List<MaterialPropertyBlock>();
foreach (var r in renderers)
{
    //Material.Get()
    Debug.LogError("Material.Get():" + r.sharedMaterial.GetColor(_dataPropID));  
    
    //MPB      
    var mpb = new MaterialPropertyBlock();
    r.GetPropertyBlock(mpb);
    mpbs.Add(mpb);
    Debug.LogError("GetMPB:" + mpb.GetColor(_dataPropID));//如果没有修改不会Log
    
    //Debug.LogError("GetXXXFromMPB:" + r.GetFloatFromMPB(_dataPropID));
}

GC Test

var renderers = gameObject.GetComponentsInChildren<Renderer>();
UnityEngine.Profiling.Profiler.BeginSample("Get sharedMaterials");
var s =  renderers[0].sharedMaterials;//gc
UnityEngine.Profiling.Profiler.EndSample();

UnityEngine.Profiling.Profiler.BeginSample("Get shader.name");
var c = s[0].shader.name;//gc
UnityEngine.Profiling.Profiler.EndSample();


renderers[i].GetFloatFromMPB(_dataPropID);//无gc
选择什么API修改材质

Editor:直接在Hierarchy上拖动材质参数相当于修改Project本地文件
Clone:如果用AnimationK动画进行修改,会创建出一个实例出来
ShareMaterial:使用 ShareMaterial会将全局的材质都修改,但不会保存到本地
所以此时,需要根据用到的情况去选择使用的API

其他

Keyword

通俗地说,Shader中的关键字就是一个个标签,方便材质在渲染时绑定不同的Shader变体,实现不同的效果。我们可以在Shader片段中使用编译指令(compile directives)来定义Shader关键字。从变体生成特点上可分为“multi_compile”和“shader_feature”两类,从作用范围角度可分为局部关键字和全局关键字。

需要说明的是,shader_feature 预编译指令行至少有两个关键字。如果只定义了一个关键字KW_X,则会默认生成一个下划线关键字。以下两行指令等价:

一般Shader片段中multi_compile类关键字每增加一个,或者启用的shader_feature类关键字增加一个,该Shader的变体数量就会增加一份。而对于变体数与内存、显存的关系,UWA曾做过以下实验:

使用#pragma multi_compile定义的一行关键字为一组,每组包含两个关键字,对产生的内存进行统计,结果如下:

由此可见变体数和ShaderLab的内存占用基本成正比。而由于没有使用Shader进行渲染,GfxDriver内存不会增加,没有参与渲染的Shader变体是不会经历CreateGPUProgram传入GfxDriver内存中的。

shader
  1. shader keyword
    需要额外的
    Material.EnableKeyword/DisableKeyword(string)
  2. 消耗查看(非真机)
    ShareMaterial 0.001ms
    SetXXX  0.001ms
    SetKeyword  0.001ms

SVC
  • 使用流程收集(multi_compile会一定生成) → 1.预生成  → 2.预热
  • 这个Shader会被编译成两个变体:一是只包含A模块代码的变体A;二是只包含B模块代码的变体B;
  • 指定的第一个关键字是默认生效的,即默认使用变体A;在脚本里用Material.EnableKeyword或Shader.EnableKeyword来控制运行时具体使用变体A还是变体B;
  • 它们声明的Keyword是全局的,可以对全局的包含该Keyword的不同Shader起作用;全局最多只能声明256个这样的Keyword;
  • )请注意Keyword的数量和变体的数量之间的关系,并可能由此导致的性能开销,比如声明#pragma multi_compile A B和#pragma multi_compile D E 这样的两组Keyword会产生 2x2=4 个Shader变体,但若声明10组这样的keyword,则该Shader会产生1024个变体
    (5)区别!!!!特别注意!!!!:
  • 如果使用shader_feature,build时没有用到的变体会被删除,不会打出来。也就是说,在build以后环境里,运行代码Material.EnableKeyword(“B”)可能不起作用,因为没有Material在使用变体B,所以变体B没有被build出来,运行时也找不到变体B

对Unity项目而言,Shader变体有其存在的积极意义。除了代码的共用与运行时渲染效果的动态改变之外,还增加了Shader程序在GPU上的执行效率。

对GPU来说,处理类似于“if-else”结构的分支语句不是它的强项,GPU的特点和功能决定了它更适合去并列地“执行”重复性的任务,而不是去“选择”。所以Shader变体的存在就很好地解决了这个问题,GPU只需要根据关键字去执行对应的Variant内容就可以,避免了性能下降的可能。同时,项目在运行时,可以通过在代码中选择不同的Shader变体,从而动态地改变着色器功能。

但是Shader变体是一把双刃剑。在带来以上便利的同时,也存在着各种问题:

1)在Build阶段,过多的Shader变体数量会使得Build耗时明显上升,而最终的项目包体体积也会变得臃肿。

2)在项目运行阶段,Shader变体会以其庞大的数量产生可观的内存占用,同时也会导致项目加载时间的增加,也就是俗说的“卡顿”。

所以本条规则会扫描项目中的Shader脚本,根据项目中Material上开启的关键字情况去计算可能生成的变体数。开发团队可以在找出这些可能生成过多变体数的Shader后,结合项目实际情况去进行相应的修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值