前一篇 Unity Standard Shader源码阅读(一) BasePass
AddPass很多处理与BasePath一致,相同的处理就不解释了;
Standard Shader第二个Pass,指定顶点着色器和片元着色器:
#pragma vertex vertAdd
#pragma fragment fragAdd
#include "UnityStandardCoreForward.cginc"
着色器定义在UnityStandardCoreForward.cginc中:
#if UNITY_STANDARD_SIMPLE
#include "UnityStandardCoreForwardSimple.cginc"
VertexOutputBaseSimple vertBase (VertexInput v) { return vertForwardBaseSimple(v); }
VertexOutputForwardAddSimple vertAdd (VertexInput v) { return vertForwardAddSimple(v); }
half4 fragBase (VertexOutputBaseSimple i) : SV_Target { return fragForwardBaseSimpleInternal(i); }
half4 fragAdd (VertexOutputForwardAddSimple i) : SV_Target { return fragForwardAddSimpleInternal(i); }
#else
#include "UnityStandardCore.cginc"
VertexOutputForwardBase vertBase (VertexInput v) { return vertForwardBase(v); }
VertexOutputForwardAdd vertAdd (VertexInput v) { return vertForwardAdd(v); }
half4 fragBase (VertexOutputForwardBase i) : SV_Target { return fragForwardBaseInternal(i); }
half4 fragAdd (VertexOutputForwardAdd i) : SV_Target { return fragForwardAddInternal(i); }
#endif
看非简化版本;
1. 顶点着色器 vertForwardAdd:
VertexOutputForwardAdd vertForwardAdd (VertexInput v)
顶点着色器输入VertexInput v与BasePass一样;
顶点着色器输出:
struct VertexOutputForwardAdd
{
UNITY_POSITION(pos);
float4 tex : TEXCOORD0;
float4 eyeVec : TEXCOORD1; // eyeVec.xyz | fogCoord
float4 tangentToWorldAndLightDir[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:lightDir]
float3 posWorld : TEXCOORD5;
UNITY_LIGHTING_COORDS(6, 7)
// next ones would not fit into SM2.0 limits, but they are always for SM3.0+
#if defined(_PARALLAXMAP)
half3 viewDirForParallax : TEXCOORD8;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
顶点着色器执行流程:
VertexOutputForwardAdd vertForwardAdd (VertexInput v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexOutputForwardAdd o;
UNITY_INITIALIZE_OUTPUT(VertexOutputForwardAdd, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
float4 posWorld = mul(unity_ObjectToWorld, v.vertex);
o.pos = UnityObjectToClipPos(v.vertex);
o.tex = TexCoords(v);
o.eyeVec.xyz = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos);
o.posWorld = posWorld.xyz;
float3 normalWorld = UnityObjectToWorldNormal(v.normal);
#ifdef _TANGENT_TO_WORLD
float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
o.tangentToWorldAndLightDir[0].xyz = tangentToWorld[0];
o.tangentToWorldAndLightDir[1].xyz = tangentToWorld[1];
o.tangentToWorldAndLightDir[2].xyz = tangentToWorld[2];
#else
o.tangentToWorldAndLightDir[0].xyz = 0;
o.tangentToWorldAndLightDir[1].xyz = 0;
o.tangentToWorldAndLightDir[2].xyz = normalWorld;
#endif
//We need this for shadow receiving and lighting
UNITY_TRANSFER_LIGHTING(o, v.uv1);
//对于平行光,_WorldSpaceLightPos0.xyz表示光源方向,w分量为0
//对于其他光,_WorldSpaceLightPos0.xyz表示光源位置,w分量为1
float3 lightDir = _WorldSpaceLightPos0.xyz - posWorld.xyz * _WorldSpaceLightPos0.w;
#ifndef USING_DIRECTIONAL_LIGHT
//非平行光,得格式化
lightDir = NormalizePerVertexNormal(lightDir);
#endif
o.tangentToWorldAndLightDir[0].w = lightDir.x;
o.tangentToWorldAndLightDir[1].w = lightDir.y;
o.tangentToWorldAndLightDir[2].w = lightDir.z;
#ifdef _PARALLAXMAP
TANGENT_SPACE_ROTATION;
o.viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
#endif
UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos);
return o;
}
再来看片元着色器:
half4 fragForwardAddInternal (VertexOutputForwardAdd i)
{
UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
FRAGMENT_SETUP_FWDADD(s) //获取BRDF输入参数,FragmentCommonData s
UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld)
//获取逐像素光源的颜色和方向
UnityLight light = AdditiveLight (IN_LIGHTDIR_FWDADD(i), atten);
//AddPath无需间接光计算
UnityIndirect noIndirect = ZeroIndirect ();
half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, light, noIndirect);
UNITY_EXTRACT_FOG_FROM_EYE_VEC(i);
UNITY_APPLY_FOG_COLOR(_unity_fogCoord, c.rgb, half4(0,0,0,0)); // fog towards black in additive pass
return OutputForward (c, s.alpha);
}
展开FRAGMENT_SETUP_FWDADD:
#define FRAGMENT_SETUP_FWDADD(x) FragmentCommonData x = \
FragmentSetup(i.tex, i.eyeVec.xyz, IN_VIEWDIR4PARALLAX_FWDADD(i), i.tangentToWorldAndLightDir, IN_WORLDPOS_FWDADD(i));
其他处理和BassPath一致,没啥好说的