编写Shader时的一些性能考虑
编写shader时的一些建议:
1、只计算需要计算的东西;
2、通常,需要渲染的像素比顶点数多,而顶点数又比物体数多很多。所以如果可以,尽量将运算从PS移到VS,或直接通过script来设置某些固定值;
3、在使用Surface Shader时,可以通过一些指令让shader优化很多。
通常情况下,Surface shader的很多默认选项都是开启的,以适应大多数情况,但是很多时候,你可以关闭其中的一些选项,从而让你的shader运行的更快:
(1) approxview 对于使用了view direction的shader,该选项会让view dir的normalize操作per-vertex进行,而不是per-pixel。这个优化通常效果明显。
(2) halfasview 可以让Specular shader变得快一些,使用一个介于光照方向和观察方向之间的half vector来代替真正的观察方向viewDir来计算光照函数。
(3) noforwardadd Forward Render时,完全只支持一盏方向光的per-pixel渲染,其余的光照全部按照per-vertex或SH渲染。这样可以确保shader在一个pass里渲染完成。
(4) noambient 禁掉ambient lighting和SH lighting,可以让shader快一点儿。
4、浮点数精度相关:
float:最高精度,通常32位
half:中等精度,通常16位,-60000到60000,
fixed:最低精度,通常11位,-2.0到2.0,1/256的精度。
尽量使用低精度。对于color和unit length vectors,使用fixed,其他情况,根据取值范围尽量使用half,实在不够则使用float。
在移动平台,关键是在fragment shader中尽可能多的使用低精度数据。另外,对于多数移动GPU,在低精度和高精度之间转换是非常耗的,在fixed上做swizzle操作也是很费事的。
5、Alpha Test
Alpha test和clip()函数,在不同平台有不同的性能开销。
通常使用它来cull那些完全透明的像素。
但是,在ios和一些android上使用的PowerVR GPUs上面,alpha test非常的昂贵。
6、Color Mask
在移动设备上,Color Mask也是非常昂贵的,所以尽量别使用它,除非真的是需要。
shader多版本编译:
shader variants(shader 变种)使用方式:
(1)#pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
(2)#pragma shader_feature FANCY_STUFF_OFF FANCY_STUFF_ON
#pragma shader_feature FANCY_STUFF是#pragma shader_feature _ FANCY_STUFF的快捷方式,同样会生成两个变种
shader_feature和multi_compile的区别:
shader_feature:未使用的变种不会build进游戏;
multi_compile:会编译生成所有变种。
用法:shader_feature更适用于材质的关键字,而multi_compile更适用于代码设置的全局关键字。
关键字个数限制:
unity最多支持256个关键字,并且unity内部已经使用了60个左右。另外,可以在unity的工程设置中定义一些全局有效的关键字,这样也会消耗一些数量,所以在编写shader时要注意数量不要超过上限。
内置的multi_compile快捷组合:
#pragma multi_compile_fwdbase 编译ForwardBase需要的所有关键字变种,包括不同的lightmap类型,主要的方向光是否开启阴影等。
#pragma multi_compile_fwdadd 编译ForwardAdd Pass包含的关键字变种。
#pragma multi_compile_fwdadd_fullshadows 和上一个类似,另外还包含了光照实施阴影的能力。
#pragma ulti_compile_fog 雾效。
上面内置的快捷方式包含了很多的变种,但可以通过skip_variants来屏蔽某些关键字:
#pragma skip_variants POINT POINT_COOKIE
硬件级别shader变种:
提供针对不同硬件(比如gles和gles 3.0)的shader变种。(针对硬件能力级别的优化)
#pragma hardware_tier_variants renderer
d3d11 - Direct3D 11/12
glcore - OpenGL 3.x/4.x
gles - OpenGL ES 2.0
gles3 - OpenGL ES 3.x
metal - iOS
/Mac Metal
vulkan - Vulkan
d3d11_9x - Direct3D 11 9.x feature level, as commonly used on WSA platforms
xboxone - Xbox One
ps4
- PlayStation 4
psp2 - PlayStation Vita
n3ds - Nintendo 3DS
wiiu - Nintendo Wii U
添加了上述#pragma的shader会自动生成三个关键字变种:
UNITY_HARDWARE_TIER1
UNITY_HARDWARE_TIER2
UNITY_HARDWARE_TIER3
编辑器模式下,可以在Graphics Emulation中来手动设置使用哪个变体。
上述三中变体,同时只会加载其中一种,
指定方式:
(1)自动检测:在加载时,Unity检测GPU并进行设置;如果检测不到,默认选择最高级。
(2)手动设置来制定使用哪一个tier,代码如下:(一定是在shader加载之前制定,在某个shader加载之后再指定是不会影响该shader的)
Graphics.activeTier = UnityEngine.Rendering.GraphicsTier.Tier1;
平台shader设置:
可以通过代码手动设置[平台, tier, 设置]
UnityEditor.Rendering.EditorGraphicsSettings.SetTierSettings(BuildTargetGroup target, GraphicsTier tier, TierSettings settings);