https://www.jianshu.com/p/429d91e63103
(1) 用step()代替if else等条件语句:(edge=step(edge,_Edge);表示if(edge<=_Edge) edge=1 , else edge=0)
在片段着色器中,以正常CPU编程的逻辑进行优化,例如,if(edge < _EdgeColor){return _EdgeColor;},如果此像素被判定为边缘,则直接返回边缘颜色,那么则不用再进行之后的运算了。但这种优化对于GPU编程来讲是无效的。再片段着色器中,每个片段着色器每条指令操作上百个像素,如果有些片段采取一个分支而有些片段不采用另一个分支,则所有片段都会执行两个分支,但只在每个片段应该采取的分之上写入寄存器。另外,if/endif等流程控制操作有较高的开销(4个时钟周期,Gefirce6系列(Nvidia))。因此在GPU编程中,ifelse,switchcase等条件语句和太复杂的逻辑是不推荐的。相应的可以用阶梯函数step()等函数进行替换,这样所有的线程都执行完全一样的代码。
(2)Shader资源解析优化。一般来说,一个Shader资源的物理Size仅几KB,在内存中也不过几十KB。所以,Shader资源的效率加载瓶颈并不在其自身大小的加载上,而是在Shader内容的解析上。一般情况下,Shader加载的CPU耗时与其Keyword数量有关,Keyword数量越多,则加载开销也越大。Shader的Keyword数量是会随着场景设置的不同而变化的。(注意:在Unity 5.x中,Unity默认会根据场景设置、Shader
Pass等来调整Shader的Keyword,比如如果存在Lightmap的使用,则会默认将对应的Keyword打开,而对于没有使用Fog的项目,则会直接将相关Keyword关闭。)减少Keyword可以尝试以下方法:
①尽量减少shader_feature和#pragma multi_compile等关键字,减小解析耗时,同时减少shader varaints(shader变体)数量,从而减少内存占用。
②通过skip_variants操作在Shader中直接去除相关Keyword,使用示例如下:
③直接去除Shader中的Fallback选项。对于使用Mobile Shader的项目,可以尝试直接将其Fallback去掉大幅降低keyword数量。
④使用AssetBundle方式加载资源,为避免大量相同的Shader被重复加载和卸载,可采用以下加载方式:通过依赖关系打包,将项目中的所有Shader抽离并打成一个独立的AssetBundle文件,其它AssetBundle与其建立依赖。Shader的AssetBundle文件在游戏启动后即进行加载并常驻内存,因为一款项目的Shader种类数量一般在50~100不等,且每个均很小,即便全部常驻内存,其内存总占用量也不会超过2MB;后续Prefab加载和实例化后,Unity引擎会通过AssetBundle之间的依赖关系直接找到对应的Shader资源进行使用,而不会再进行加载和解析操作。(注意:对于Unity4.x版本,Shader的AssetBundle加载后只需LoadAll即可完成所有Shader的加载和解析,但对于Unity5.x版本,除执行LoadAllAssets操作外,还需要进行Shader.WarmupAllShaders操作(因为在Unity5.x版本中,Shader的解析和CreateGPUProgram操作是分离的),保证实际需要的Shader variants被完全加载,避免游戏过程中编译Shader导致的hiccups(卡顿)。新的Unity版本中已由ShaderVariantCollection.WarmUp()代替Shader.WarmupAllShaders操作。)
作者:不正经的搬砖工
链接:https://www.jianshu.com/p/429d91e63103
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。