下面是built-in着色器的源码:
为什么i.ray = lerp(UnityObjectToViewPos(v.vertex)) * float(-1, -1, 1)里要乘 float3(-1, -1, 1)?请看代码下面的注释
#pragma vertex vert_deferred
#pragma fragment frag
struct unity_v2f_deferred {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 ray : TEXCOORD1;
};
float _LightAsQuad;
// 顶点着色器
unity_v2f_deferred vert_deferred (float4 vertex : POSITION, float3 normal : NORMAL)
{
unity_v2f_deferred o;
o.pos = UnityObjectToClipPos(vertex);
o.uv = ComputeScreenPos(o.pos);
// 乘以float3(-1, -1, 1)是为了配合片元着色器里面(UnityDeferredCalculateLightParams函数第一行)计算rayToFarPlane的操作,
//因为视口空间是右手坐标系,摄像机前的坐标z值都是负数,而_ProjectionParams.z(far)是正数。
// 例如所以当视口坐标(-1,-1,-1)代入i.ray * _ProjectionParam.z / i.ray.z之后x和y会变成正数(相反数),
//所以在这里提前反转一下x和y,以免后续计算错误。而这里乘float3(1, 1, -1)同样可以避免错误。
o.ray = UnityObjectToViewPos(vertex) * float3(-1,-1,1);
// normal contains a ray pointing from the camera to one of near plane's
// corners in camera space when we are drawing a full screen quad.
// Otherwise, when rendering 3D shapes, use the ray calculated here.
o.ray = lerp(o.ray, normal, _LightAsQuad);
return o;
}
#ifdef UNITY_HDR_ON
half4
#else
fixed4
#endif
// 片元着色器
frag (unity_v2f_deferred i) : SV_Target
{
half4 c = CalculateLight(i);
#ifdef UNITY_HDR_ON
return c;
#else
return exp2(-c);
#endif
}
half4 CalculateLight (unity_v2f_deferred i)
{
float3 wpos;
float2 uv;
float atten, fadeDist;
UnityLight light;
UNITY_INITIALIZE_OUTPUT(UnityLight, light);
UnityDeferredCalculateLightParams (i, wpos, uv, light.dir, atten, fadeDist);
light.color = _LightColor.rgb * atten;
// unpack Gbuffer
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
UnityStandardData data = UnityStandardDataFromGbuffer(gbuffer0, gbuffer1, gbuffer2);
float3 eyeVec = normalize(wpos-_WorldSpaceCameraPos);
half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb);
UnityIndirect ind;
UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
ind.diffuse = 0;
ind.specular = 0;
half4 res = UNITY_BRDF_PBS (data.diffuseColor, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, -eyeVec, light, ind);
return res;
}
void UnityDeferredCalculateLightParams (
unity_v2f_deferred i,
out float3 outWorldPos,
out float2 outUV,
out half3 outLightDir,
out float outAtten,
out float outFadeDist)
{
i.ray = i.ray * (_ProjectionParams.z / i.ray.z); // 得到摄像机到远裁切面方向向量
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
depth = Linear01Depth (depth);
float4 vpos = float4(i.ray * depth,1);
float3 wpos = mul (unity_CameraToWorld, vpos).xyz; // 这里的vpos不是视口空间坐标,而是z值反转的视口空间坐标。详细解析:https://blog.youkuaiyun.com/zengjunjie59/article/details/113033567
float fadeDist = UnityComputeShadowFadeDistance(wpos, vpos.z);
// spot light case
#if defined (SPOT)
float3 tolight = _LightPos.xyz - wpos;
half3 lightDir = normalize (tolight);
float4 uvCookie = mul (unity_WorldToLight, float4(wpos,1));
// negative bias because http://aras-p.info/blog/2010/01/07/screenspace-vs-mip-mapping/
float atten = tex2Dbias (_LightTexture0, float4(uvCookie.xy / uvCookie.w, 0, -8)).w;
atten *= uvCookie.w < 0;
float att = dot(tolight, tolight) * _LightPos.w;
atten *= tex2D (_LightTextureB0, att.rr).r;
atten *= UnityDeferredComputeShadow (wpos, fadeDist, uv);
// directional light case
#elif defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE)
half3 lightDir = -_LightDir.xyz;
float atten = 1.0;
atten *= UnityDeferredComputeShadow (wpos, fadeDist, uv);
#if defined (DIRECTIONAL_COOKIE)
atten *= tex2Dbias (_LightTexture0, float4(mul(unity_WorldToLight, half4(wpos,1)).xy, 0, -8)).w;
#endif //DIRECTIONAL_COOKIE
// point light case
#elif defined (POINT) || defined (POINT_COOKIE)
float3 tolight = wpos - _LightPos.xyz;
half3 lightDir = -normalize (tolight);
float att = dot(tolight, tolight) * _LightPos.w;
float atten = tex2D (_LightTextureB0, att.rr).r;
atten *= UnityDeferredComputeShadow (tolight, fadeDist, uv);
#if defined (POINT_COOKIE)
atten *= texCUBEbias(_LightTexture0, float4(mul(unity_WorldToLight, half4(wpos,1)).xyz, -8)).w;
#endif //POINT_COOKIE
#else
half3 lightDir = 0;
float atten = 0;
#endif
outWorldPos = wpos;
outUV = uv;
outLightDir = lightDir;
outAtten = atten;
outFadeDist = fadeDist;
}