不同的光照模型被选择的顺序
渲染路径和pass的LightMode标签
Unity支持3种RenderingPath,分别是VertexLit,Forward,和Deferred Lighting。Pass中使用的LightMode标签Vertex,ForwardBase,ForwardAdd,PrepassBase,PrepassFinal,表示当前Pass是为在哪一个RenderingPath下设计使用的。
设计一个只会在摄像机单位渲染路径为Deferred模式下才会输出红色的Shader
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
Blend One One
CGPROGRAM
#pragma surface surf MyDeferred
half4 LightingMyDeferred_PrePass (SurfaceOutput s, half4 light) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo=float3(1,0,0);
}
ENDCG
}
再就是Deferred_Forward.Shader,包含可以适应Deferred以及Forward渲染路径的材质,适应Deferred输出红色,适应Forward输出绿色;
SubShader {
Blend One One
//.1
pass{
Tags{ "LightMode"="ForwardBase"}
Blend One One
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=float4(0,1,0,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
//.2
CGPROGRAM
#pragma surface surf MyDeferred
half4 LightingMyDeferred_PrePass (SurfaceOutput s, half4 light) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo=float3(1,0,0);
}
ENDCG
}
然后是Deferred_Forward_Vertex.Shader,这个Shader添加了可以适应VertexLit渲染路径的pass会输出蓝色,如果三个都执行就是混合色白色。
SubShader {
Blend One One
//.1
pass{
Tags{ "LightMode"="Vertex"}
Blend One Zero
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=float4(0,0,1,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
//.2
pass{
Tags{ "LightMode"="ForwardBase"}
Blend One One
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=float4(0,1,0,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
//.3
CGPROGRAM
#pragma surface surf MyDeferred
half4 LightingMyDeferred_PrePass (SurfaceOutput s, half4 light) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo=float3(1,0,0);
}
ENDCG
}
最后还有Deferred_Vertex.Shader与上面的类似不过去掉了Forward渲染路径的部分,还有去掉Deferred部分的Forward_Vertex.Shader。以上的Shader所有针对Deferred渲染路径的Pass最终都会输出红色,Forward的Pass输出绿色,VertexLit最终输出蓝色。
总结:Unity在VertexLst渲染路径下,只会寻找可在VertexLit渲染模式下的Pass然后返回。在Deferred渲染路径下,则先寻找可在Deferred渲染模式下的Pass并返回,如果找不到,则会寻找Forward模式下的Pass并返回,如果依然没找到,则会寻找VertexLit模式下的Pass并返回。在Forward渲染路径下,会优先寻找Forward模式下可渲染的Pass,如果找不到寻找VertexLit模式下可渲染的Pass。
除了传统的3个渲染路径之外,Pass的LightMode标签还可以设置为Always或者不设置。
下面代码用于输出绿色
SubShader {
pass{
Tags{ "LightMode"="Always"}
Blend One One
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=float4(0,1,0,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
}
然后是Deferred_Always,有一个针对Deferred渲染路径的表面着色器,其次是一个Always Pass,混合模式是Blend One Zero。如果Always在Surface Shader之后执行,就会只显示自己输出的绿色,反之输出混合之后的黄色
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
Blend One One
CGPROGRAM
#pragma surface surf MyDeferred
half4 LightingMyDeferred_PrePass (SurfaceOutput s, half4 light) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo=float3(1,0,0);
}
ENDCG
pass{
Tags{ "LightMode"="Always"}
Blend One Zero
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=float4(0,1,0,1);
return o;
}
float4 frag(vertOut i):COLOR
{
return i.color;
}
ENDCG
}//end pass
}
针对VertexLit渲染路径的Shader中,Always Pass的执行和在代码中的位置有关系,在代码中靠前,则先执行,然后被混合模式为Blend One One的Vertex Pass中输出红色混合为黄色,在代码中靠后则后执行,混合模式为Blend One Zero所以输出是绿色。到Forward模式下,Always Pass也是按照在代码中位置来执行。而Deferred模式下,Always pass不执行现实的结果就是表面着色器的结果。如果没有设置光照模型,跟Always的一样。