深入UE4材质管理

UE4的材质系统使用起来虽然很方便,但是如果不进行有效的管理,很快就会导致项目的体积变得不可控制,材质编译时间也会变成痛苦的折磨。

本文是EpicJapan UE4 DeepDive系列中材质管理部分的总结,对应UE4版本为4.12~14。部分截图来自4.18。

抽离共通逻辑

为了减少材质的编译尺寸,首先要做的就是将共通的逻辑都抽出来。

在材质系统中一共有以下两种做法

Material Function

材质函数可以将一些共同的操作逻辑抽取出来,这样在进行材质的编译的时候,就不会产生重复的部分了。

UE4本身就提供了大量的材质函数来方便进行材质的表现。

Material Instance

材质实例通过将通用的材质统合起来,有效的减少材质的数量。

使用上,如果材质之间就只有贴图或者参数不同的话,就可以构建一个基础的材质,然后将需要变化的材质进行参数化。

并创建材质实例以应对不同的情况。

选项优化

材质在使用时有的选项需要进行优化,否则就会生成很多不会使用到的部分。导致编译时间变长且无端的占用发布体积。

Usage

材质的选项中有一个Usage的选项,通常会自动勾选上Automatically Set Usage in Editor。

这个选项会在材质被特定的Usage使用的时候自动打开,针对每一种Usage会生成新的Shader来进行对应。

但是,Usage被打开后,如果不再在对应的Usage中使用的话,引擎并不会自动的关闭这个Usage,所以需要手动的进行关闭。

这个选项的作用在极端情况下特别大:使用全部Usage时1837K的材质在仅使用Static Light时却只有97K的。

因此在使用的时候还是需要进行额外的注意的,如果默认去掉这个选项的话,就可以有效的避免误操作导致的勾选了。当然使用起来就会有些麻烦。

Shader Permutation Reduction

在项目设置>渲染中,能够看到

image

这个也是类似的选项,在没有使用对应的功能的时候去掉就好了。

这个如果去掉了却在使用对应的功能的话,编辑器内会有屏幕输出提示,可以放心使用。

材质实例关系

材质实例的继承关系会很大的影响到材质的编译过程,部分继承的属性重写是会导致材质实例需要生成新的Shader的。

Override properties

材质属性覆盖会导致需要为实例生成新的Shader

image

Static Switch Parameter

开关是需要额外的生成Shader的

image

当然也包括Static Component Mask Parameter。

 

因此在进行材质实例的继承的时候,应当进行规划,首先分支出Switch等需要重新生成Shader的材质实例后,再继承其他的如贴图、颜色这些不会导致重新生成的材质实例的继承。

同时,由于材质实例不携带Usage属性,所以这个问题上只能一开始就进行分开。

Tips

这个是SE的演讲者给出的一些操作建议。

Textrue

尽量减少图形的分辨率,在使用单色的Textrue时,使用1×1的图片即可,在需要过渡特效时,使用一个小条就可以了。

image

而有对称性的图片,可以通过调整Tilling Method来减小尺寸。

image

Mipmap

有一个ComputeMipLevel的节点可以用于将Mipmap进行可视化调节。

Mipmap虽然可以在贴图的选项中关掉,但是这样会导致原始贴图常驻内存,运行时消耗很大。

Texture的Uv入口被用于缩放时并不会对应到MipLevel上,使用时需要注意。

Power

不要使用Power来进行2.2次方的运算而是直接相乘。也可以直接将同一个数相乘写成一个材质函数,方便使用。

因为两个的计算几乎无法目视区分,却有着明显的性能消耗。

vector displacement map

矢量置换贴图采用BC7压缩可以大幅减小尺寸?

Maximum Texture Size

比LOD Bias能够更好的对贴图尺寸进行控制。

Never Stream

会一次性载入所有的MipLevel贴图,在使用频率很高的粒子的贴图上可以打开。

Material

除0対策

为了防止0被传到除法运算上,可以考虑加上0.0001,虽然严格意义上应当使用Max或者Min来进行控制,但是Add的效率更高

Texture参数

即便两个参数指定的是同一个Texture,也会进行两次采样。

SamplerType

SamplerType选择为Alpha时在有的平台实际上用的确实R通道

Trick

DynamicParameter 对于float2、float3、float4,如果实际上需要的参数是一样的话,是可以用float来代替的,会自动的被变为对应的类型。

ParticleColor 可以在EmissiveColor不需要通过这个参数指定时用于其他用途

ParticleRandom是GPU粒子独有的节点,值在0~1之间,可以用于添加随机特效

Static Component Mask Parameter可以为1张贴图提供四种变数

UV使用Time进行滚动时,可以先滚动再Tilling,这样的话Tilling进行调整时就不会影响UV动画的速度了。

本博客所有内容遵循CC BY-NC-SA 4.0协议, 如有转载,请注明出处。
4 条评论

    bSharedMaterialShaderCode是shader编译时不inline还是继续采用include方式的选项吧,能显著减少包体体积

    bSharedMaterialNativeLibraries可能也能减小包体,但我个人测试好像没什么用(或者说只对Metal有效?)

     

    要是博主能再写一些mobile material,还有巨坑r.MobileHDR cook的逻辑就好了


    截图里的Use shared movable point light shaders确实是应该勾上才能减少体积,当时一股脑截图进来了,没怎么留意到呢。
    bSharedMaterialNativeLibraries这个选项看注释应当是平台相关的,如果在其他地方做过平台相关优化的估计对体积影响不大,不过我并没有测试过。

    mobile material这一块没有怎么深入探索过,目前公司的项目是Win平台的。


    国内做win平台感觉还真的不多啊。而且博主能用c++,很羡慕,感觉放在我现在东家业务层用c++绝对是要申请的。现在东家花了大代价开发了wlua,和unity的slua在上级接口保持一致,业务层完全使用lua搞。

    而且UE4做desktop和console感觉很合适,做mobile体验就不太好了

    mobile包体体积很大,策划那边跟我说包每增大100m会减少多少多少潜在用户,然后这边就得想办法减小包体。

    并且UE4在包体体积上真的没有精益求精,uasset文件经常拿zip压缩还能压,结果现在我们cook的时候都不用UE4的压缩而是自己用lz4压。UE4在音频上也很豪放,在ios上只用adpcm(压缩比1:4),搞得现在还在评估要不要引入fmod,wwise或者criware

    不知道是不是Epic的人故意留坑卖服务,还顺便给友商们也继续留条财路一起发财


    因为以前是做cocos2d-x的所以对C++比较熟悉,不过相对的学习shader这一块时费了好大的劲。目前在做的产品严格来说并不能算是在做游戏而更接近于硬件,所以并没有一个独立的业务层的需求呢。
    mobile体积和audio engine这一块记得这几次版本更新都有在做,不过由于用不到所以没有怎么关注过。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">