在接下来两个章节,将要学习怎样使Shader在不同平台下都有良好的表现。我们不去讨论任何一个特定的平台,而是去分解Shader中我们可以进行调整的各个部分,讨论一般情况下的移动平台优化。这其中包括了,Unity内置变量的介绍,如何减少Shader内存等等。
+ 什么是Cheap shader
+ 分析你的shader
+ 为移动平台修改shader
shader的优化,几乎在每一个游戏项目都会遇到。常常有一个关注的点,例如用更新的纹理实现相同的效果。作为一个技术美术,一个shader程序员,你必须明白shader优化的基本原理,这样才可以实现性能提高的同时保持相对较好的效果。拥有了这些知识,还会对你编写shader有所帮助。例如,你知道你们游戏是运行于移动设备之上的,我们可以把所有的光照函数使用Half vector近似模拟,而不是直接计算反射向量。
这又点难以回答,对于shader有很方面可以去做优化是的它更有效率。有可能是内存纹理,纹理数量问题,有可能是shader本身很好的工作,但我们可以使用更少的数据,代码去实现相同的效果。我们需要去探索这些相关的技术,和怎么样去组合它们使得你的shader又快有保持一定的高质量效果,无论在PC还是移动设备上。
几个优化方面:
+ ### 数据类型
+ Float: 32位,浮点数, 精度高,但在3中浮点数中最慢。
+ Half: 16位,浮点数,[-60000, 60000], 精确到小数点后3位,适合存储UV值,颜色值,比float要快。
+ Fixed: 通常是11位,定点数?范围在[-2, 2] 精度1/256,这个精度设置非常适合颜色运算。
那么,很多时候我们想要去控制那个作为主光源进行逐像素的计算?这可以同光光源的Inspector面板上的RenderMode进行控制,有3个选项
+ Auto 由Unity决定最佳的行为。
+ Important 尽可能进行逐像素处理
+ Not Important 进行逐顶点处理
通过这些选项你可以告诉Unity那些光源应该更应该被认为是需要逐像素处理的光源,反之,那些不应该进行逐像素处理。
shader code
Shader "CookbookShaders/self/OptimizeShader001" {
Properties {
_MainTex ("Base (RBG)", 2D)="white"{}
_NormalMap("Normal Map", 2D)="bump"{}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
//define light function ourself, noforwardadd?
//excluce_path:prepass
#pragma surface surf SimpleLambert excluce_path:prepass noforwardadd
sampler2D _MainTex;
sampler2D _NormalMap;
struct Input {
half2 uv_MainTex; //float2 to half2 ,save data
//half2 uv_NormalMap; remove uv of normalmap ,because same as uv maintex
};
inline float4 LightingSimpleLambert(SurfaceOutput s, float3 lightDir, float atten)
{
//float to fixed save data
fixed diff = max(0, dot(s.Normal, lightDir));
fixed4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
c.a = s.Alpha;
return c;
}
void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
}
ENDCG
}
FallBack "Diffuse"
}
Unity提供的Prefiling可以让我们实时的了解运行过程中,每一个对象对于各种资源的消耗。
更多信息可以参考官方文档:https://docs.unity3d.com/Manual/MobileProfiling.html
到现在我们实践过一些Shader的优化技巧,现在让我们来看看怎么为移动平台写一个漂亮,高质量的Shader。
Shader "CookbookShaders/self/mobilespeclar" {
Properties{
_Diffuse("Base (RGB) Specular Amount (A)", 2D) = "white" {}
_SpecIntensity("Specular Width", Range(0.01, 1)) = 0.5
_NormalMap("Normal Map", 2D) = "bump" {}
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
//define light function ourself, noforwardadd only one direct light should per-pixel
//excluce_path:prepass
//halfasview
#pragma surface surf MobileBlinnPhong nolightmap noforwardadd halfasview
sampler2D _Diffuse;
sampler2D _NormalMap;
fixed _SpecIntensity;
struct Input {
half2 uv_Diffuse;
};
inline float4 LightingMobileBlinnPhong(SurfaceOutput s, fixed3 lightDir, fixed halfDir, fixed atten)
{
fixed diff = max(0, dot(s.Normal, lightDir));
fixed nh = max(0, dot(s.Normal, halfDir));
fixed spec = pow(nh, s.Specular * 128) * s.Gloss;
fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
c.a = 0.0;
return c;
}
void surf(Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_Diffuse, IN.uv_Diffuse);
o.Albedo = c.rgb;
o.Alpha = 0.0;
o.Specular = _SpecIntensity;
o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_Diffuse));
}
ENDCG
}
FallBack "Diffuse"
}
最后,需要知道保证只使用你真正所需要的数据,要对游戏在目标平台下的效果做权衡。