7.3重要光源在ForwardAdd内的执行
此外我们知道,根据Unity在关于Forward RenderingPath的官方帮助文档的陈述,除了第一个Pixel平行光之外,每个其他Pixel光源都会在个单独的ForwardAdd Pass内被执行,也就是说场景中的Pixel光源数为n,则ForwardAdd Pass会被执行n-1次。下面就来验证每一个其他Pixel光源是在ForwardAdd Pass内被执行的。
7.3.1设计用来检测Pixel光源的材质
Lab_1c文件夹下的场景,其编辑器截图如下图所示,左下角的小球被赋予一个默认材质,左边的大球使用的是_Indicator/ForwardBase文件夹下的_WorIdSapceLightPos0.shader,该Shader只计算了ForwardBase内的_WorldSapceLightPos0的光照效果。而右边的大球则使用了Lablc/Shader文件夹里的_WorIdSpaceLightPos0.shader,该Shader在ForwardBase内的输出为(0,0,
0, 1),保证了只会输出FowardAdd内的结果,而具体的ForwardAdd Pass则使用了Blend OneOne的混合模式,因此都是在上一个ForwardAdd的基础上叠加的效果。
下面是_Indicator/ForwardBase/_WorldSapceLightPos0.shader的代码:
Shader "Tut/Lighting/Forward/Indicator/Base/_WorldSpaceLighPos0" { Properties {//这个一个只计算了ForwardBase内的_WorldSpaceLightPos0光照的Shader _Color ("Base Color", Color) =(1,1,1,1) } SubShader { pass{ Tags{ "LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" uniform float4 _Color; struct vertOut{ float4 pos:SV_POSITION; float4 color:COLOR; }; vertOut vert(appdata_base v) { float3 n=(mul(float4(v.normal,0.0),_World2Object)).xyz; n=normalize(n); float4 lightDir; float dist; float4 diffColor=float4(0,0,0,0); float diff=0; float atten=1; float4 worldSpaceVertex=mul(_Object2World,v.vertex); //first light 第一个重要光源 float4 lightPos=_WorldSpaceLightPos0; if(lightPos.w==0)//direction 此条件可判断光源是否为平行光 { lightDir=lightPos; atten=1.0; }else//Point/Spot 否则是点光源 { lightDir=lightPos-worldSpaceVertex; atten=1/(1+length(lightDir)); lightDir=normalize(lightDir); } diff=max(0.0,dot(n,lightDir.xyz)); diffColor=_LightColor0*_Color*diff*atten; vertOut o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.color=diffColor; return o; } float4 frag(vertOut i):COLOR { return i.color; } ENDCG }//end pass } }
下面是Lab_1c/_Shader文件夹里_WorldSpaceLightPos0.shader的代码:
Shader "Tut/Lighting/Forward/Lab_1c/_WorldSpaceLighPos0" { Properties { _Color ("Base Color", Color) =(1,1,1,1) } SubShader { pass{ Tags{ "LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" uniform float4 _Color; struct vertOut{ float4 pos:SV_POSITION; float4 color:COLOR; }; vertOut vert(appdata_base v) { vertOut o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.color=float4(0,0,0,1);//通过输出黑色,去掉ForwardBase的影响 return o; } float4 frag(vertOut i):COLOR { return i.color; } ENDCG }//end pass pass{//这个ForwardAdd内的光源才是我们需要检测的 Tags{ "LightMode"="ForwardAdd"} Blend One One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" uniform float4 _Color; struct vertOut{ float4 pos:SV_POSITION; float4 color:COLOR; }; vertOut vert(appdata_base v) { float3 n=(mul(float4(v.normal,0.0),_World2Object)).xyz; n=normalize(n); float4 lightDir; float dist; float4 diffColor=float4(0,0,0,0); float diff=0; float atten=1; float4 worldSpaceVertex=mul(_Object2World,v.vertex); //first light 第一个重要光源 float4 lightPos=_WorldSpaceLightPos0; if(lightPos.w==0)//direction 此条件可判断光源是否为平行光 { lightDir=lightPos; atten=1.0; }else//Point/Spot 否则为点光源 { lightDir=lightPos-worldSpaceVertex; atten=1/(1+length(lightDir)); lightDir=normalize(lightDir); } diff=max(0.0,dot(n,lightDir.xyz)); diffColor=_LightColor0*_Color*diff*atten; vertOut o; o.pos=mul(UNITY_MATRIX_MVP,v.vertex); o.color=diffColor; return o; } float4 frag(vertOut i):COLOR { return i.color; } ENDCG }//end pass } }
7.3.2设计检测用的场景
场景中存在一个足够强大的黄色Pixel平行光,强大到可以保证它一定会被ForwardBase内的_WorldSpaceLightPos0所捕捉,从而不会让任何其他Pixel光源落到ForwardBase内,而只会被放到ForwardAdd Pass的_WorIdSpaceLightPos0内。最后,场景中还有5个RenderMode为Not
Important,即Vertex光源,其色彩分别为青色、橙色、绿色、红色和蓝色。
7.3.3检测结果:ForwardAdd如何被执行
编译并运行此场景,然后依次将5个Vertex光源设为Pixel,结果如图7.8所示,右边的大球体依次被染上了青色、橙色、绿色、红色和蓝色(根据你的改变次序,顺序会稍有差异)。现在我可以负责任地告诉大家,针对这5个Pixel光源,模式为Blend One One的ForwardAdd Pass确确实实被执行了5次。
返回到上一个场景,即Lab_1下面的那个场景,把光源不停地在Pixel和Vertex模式,以及Point和Direction模式问切换,可以发现,对于将会被传递到ForwardAdd内的每一个Pixel光源,Unity也是按照强弱的顺序依次让它们在ForwardAdd Pass内执行的。