作用:
在裁剪空间中的线性增加Z坐标的值
偏移片元在光源空间下的裁剪坐标,用于解决shadow acne(阴影失真)的问题。该偏移作用于光源生成阴影深度图的时候。
原理:
通过减少光源到物体的深度图的数值(距离越远数值越小),从而使光源到物体表面片元的距离数值增加,在比较物体片元到摄像机的距离和到光源的距离时,到光源的距离比真实数值更远一点,通过距离比较之后,把处于边界值的片元都当作被光源照射到。
如下图,如果不启用bias,ad片元能被照射到,而bc片元则不能被照射到。详细说明:https://blog.csdn.net/lawest/article/details/106364935
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | float4 UnityApplyLinearShadowBias(float4 clipPos) { #if defined(UNITY_REVERSED_Z) // We use max/min instead of clamp to ensure proper handling of the rare case // where both numerator and denominator are zero and the fraction becomes NaN. // Direct3D11-like clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0)); float clamped = min(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE); #else // Direct3D9-like OpenGL-like clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w); // float clamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE); #endif clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y); return clipPos; } |
源码分析:(本人并不确定,望指教)
clipPos.z += saturate(unity_LightShadowBias.x/clipPos.w);:
clipPos是裁剪空间下的齐次坐标:(N * x, N * y, az + b, -z), 其中x,y,z分别是相机空间下的坐标数值
unity_LightShadowBias.x是一个负数,默认一般是-0.0005,除以clipPos.w也就是除以相机空间下的-z,可以知道为了补偿透视投影,这里除以clipPos.w之后片元距离光源越远偏移量越小。近大远小?至于数学层面的分析本人还不清楚。
float clamped = max(clipPos.z, clipPos.w*UNITY_NEAR_CLIP_VALUE);:
UNITY_NEAR_CLIP_VALUE是NDC空间下z的最小值。这行代码就是当clipPos.z比近裁切面还要小的时候取近裁切面的值
clipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y);:
unity_LightShadowBias.y, 当光源是平行光的时候该值为1,其他光源为0,当是平行光时最后clipPos直接取clamped的值,这是为了避免在平行光原点背面的片元的深度也保持在0~1,当然平行光并没有原点,这里这是方便计算。当不是平行光的时候该值为0,相当于直接取上面偏移bias之后的clipPos的值。
应用: