第7章 Forward渲染路径
本章的主要目的是让大家在不使用Unity的Surface Shader时,也能够正确地存取Unity的光源数据,从而定制自己的Forward渲染路径的Shader。如果读者没有这个需求,或者己经了解了Unity是如何为Forward渲染路径存放光源数据的,那么就可以跳过本章。
7.2Forward渲染路径下的重要光源
7.2.1 设计检测用的材质
其编辑器截图如图所示,
_WorldSpaceLightPosO.x.shader文件,其主要代码如下:
Shader "Tut/Lighting/Forward/Lab_1/Add/_WorldSpaceLighPos0.x" { SubShader { pass{ Tags{ "LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" 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.5,1,1);//输出蓝色 return o; } float4 frag(vertOut i):COLOR { return i.color; } ENDCG }//end pass pass{ Tags{ "LightMode"="ForwardAdd"} Blend One Zero//该混合模式消去Forward Base的影响 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" 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=_WorldSpaceLightPos0.x;//有4个类似这样的Shader,分别输出xyzw分量 return o; } float4 frag(vertOut i):COLOR { return i.color; } ENDCG }//end pass } }
这个材质的ForwardAdd Pass使用了Blend One Zero的混合模式,因此可以正确地输出最后执行的ForwardAdd Pass的输出,而且,如果ForwardAdd Pass末被执行,将会输出ForwardBase Pass的结果,即输出1个鲜亮的蓝色(0,0.5,1.0)。
7.2.2不存在Pixel光源时的情况
当前场景中有两个平行光和4个点光源,但是全为Vertex光源。现在我们可以将此场景编译运行一下,其结果如下图所示。可见到在LightMode = ForwardBase的Pass内_WorIdSapceLightPos0没有被设置一个光源数据,而右边的信号输出全是ForwardBase Pass输出的鲜亮的蓝色,这说明当前情况下的ForwardAdd Pass没有被执行。
7.2.3存在Pixel平行光时的情况
我们将一个平行光改为Pixel光源,其结果如下图所示,在FowardBase的Pass内,_WorldSpaceLightPos0和_LightColor0有了数据,但是右边的鲜蓝色信号输出告诉我们此时FowardAdd Pass仍没有被执行。
7.2.4存在Pixel点光源时的情况
如果此时我们再将一个或者多个点光源设为Pixel光源,而没有Pixel平行光,可以看到如下图所示的结果,右边的信号输出显示ForwardAdd Pass包含光源数据且被执行。左边的FowardBasePass内_WorldSpaceLightPosO内有数据,但是对应的_LightColor0没有,这样使用_WorldSpaceLightPos0和_LightColor0的组合输出仍然是黑色,对最终的光照没有影响。
这种情形的存在原因,是Unity为FowardAdd Pass准备的光源数据在再次轮回到为FowardBase准备数据时Unity未及时清除的结果。Unity出于性能方面的考虑,因为毕竟在CPU和GPU之间频繁传递数据是很耗资源的一件事情。
7.2.5 Forward渲染路径下的Pixel光源小结
至此我们可以总结,在LightMode = ForwardBase,LightMode=FowardAdd的Pass内,_WorldSapceLightPos0只会含有Pixel光源。在ForwardBase Pass内,只有场景中存在RenderMode为Important的Pixel平行光时,才会含有有效的_WorldSpaceLightPos0和_LightColor0的组合。