UnityApplyLinearShadowBias -- Unity中計算陰影bias的方法

zengjunjie59發表於2020-12-11

 

 

作用:

偏移片元在光源空間下的裁剪座標,用於解決shadow acne(陰影失真)的問題。

原理:

通過減少光源到物體的深度圖的數值(距離越遠數值越小),從而使光源到物體表面片元的距離數值增加,在比較物體片元到攝像機的距離和到光源的距離時,到光源的距離比真實數值更遠一點,通過距離比較之後,把處於邊界值的片元都當作被光源照射到。

如下圖,如果不啟用bias,ad片元能被照射到,而bc片元則不能被照射到。詳細說明:https://blog.csdn.net/lawest/article/details/106364935

preview

原始碼:

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的值。

 

相關文章