天天看點

陰影漸變衰減UnityComputeShadowFadeDistance與UnityComputeShadowFade

這兩個方法用于計算陰影漸變衰減

1,UnityComputeShadowFadeDistance:

源碼:

float UnityComputeShadowFadeDistance(float3 wpos, float z)
{
    float sphereDist = distance(wpos, unity_ShadowFadeCenterAndType.xyz);
    return lerp(z, sphereDist, unity_ShadowFadeCenterAndType.w);
}
           

作用:計算世界坐标到陰影衰減中心的距離。

原理:

傳入的兩個參數分别是:片元的世界坐标,片元視口空間下的z值

衰減中心有兩種類型:1:位于相機位置的前方0.2666(1/3.75)倍陰影距離處,下面稱為偏移衰減中心。2:位于錄影機所在坐标

unity_ShadowFadeCenterAndType.w:存儲着衰減類型,數值是0或者1,0代表為偏移衰減中心,1代表衰減中心位于錄影機所在坐标

unity_ShadowFadeCenterAndType.xyz:當衰減中心偏移到錄影機前面2.66666倍陰影距離的時候(衰減中心是錄影機坐标的時候xyz分量沒有意義),unity_ShadowFadeCenterAndType.xyz儲存的是陰影衰減中心的世界坐标。數值上等于camPos +  normalize( camFront ) * 0.26666f * shadowDistance,其中shadowDistance是陰影距離對應我們的設定ProjectSettings -> Quality -> Shadows -> Shadow Distance。

2,UnityComputeShadowFade:

half UnityComputeShadowFade(float fadeDist)
{
    return saturate(fadeDist * _LightShadowData.z + _LightShadowData.w);
}
           

作用:根據片元到衰減中心的距離計算陰影衰減值,傳回數值範圍是0~1,0表示沒有衰減,1表示全衰減。

原理:

_LightShadowData.x = 1.0 - shadow_strength                                                            // shadow_strength就是燈光元件裡面的陰影強度,Strength(0~1)

_LightShadowData.y = max(camera_far_clip / shadow_distance, 1.0)                       // 但未在目前内置着色器代碼庫中使用

_LightShadowData.z = 5.0f * 1 / min(camera_far_clip, shadow_distance)                 // 不太确定,但看起來是這樣的

_LightShadowData.w = -1.0f * (2.0f + camera_field_of_view / 180.0f * 2.0f)               // 正交時,fov被視為0

以偏移衰減中心以及shadow_distance = 100 、camera_far_clip = 1000,camera_field_of_view = 60為例:

陰影漸變衰減UnityComputeShadowFadeDistance與UnityComputeShadowFade

o點為錄影機位置,a點位偏移衰減中心,位于錄影機前0.266666倍陰影距離處(26.66666),以a點為圓心,畫一個半徑為1 - 0.266666被陰影距離的圓,這個圓就是陰影投影區域。

當shadow_distance = 100 、camera_far_clip = 1000,camera_field_of_view = 60時,_LightShadowData.z = 1 / 20, _LightShadowData.w = -2.66667

現在計算最遠處片元的陰影衰減:預期計算結果應該是1,全衰減,即最遠處陰影應該衰減到沒有。

最遠處片元到衰減中心的距離是73.33333333,

代入fadeDist * _LightShadowData.z + _LightShadowData.w = 73.333 * 1/20 - 2.667 = 3.667 - 2.667 = 1。與預期一樣

計算五分之四處片元的陰影衰減:預期計算結果應該是0,從4/5倍陰影距離開始衰減。五分之四處到衰減中心的距離是100 * 4/5 - 26.667 = 53.333

代入fadeDist * _LightShadowData.z + _LightShadowData.w = 53.333 * 1/20 - 2.667 = 2.667 - 2.667 = 0。與預期一樣

由此可知,從shadow_distance的五分之四處,開始漸變衰減,到了五分之五處漸變成全衰減。

用法:

// 直接光(uv:螢幕空間坐标,worldPos:片元世界坐标,viewZ:片元視口空間z值)
UnityLight CreateLight(float uv, float3 worldPos, float viewZ){
    UnityLight light;
    light.dir = -_LightDir;          // 光源到片元的向量轉換成片元到光源的向量
    float shadowAttenuation = 1;     // 陰影,1表示沒有陰影
    #if defined(SHADOWS_SCREEN)      // 判斷是否啟用了螢幕空間陰影
        shadowAttenuation = tex2D(_ShadowMapTexture, uv).r // 從陰影貼圖采樣陰影值

        // 得到片元與陰影衰減中心的距離
        float shadowFadeDistance = UnityComputeShadowFadeDistance(worldPos, viewZ)
        // 得到陰影衰減值
        float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
        // 把陰影衰減應用到陰影值裡
        shadowAttenuation = saturate(shadowAttenuation + shadowFade);
    #endif
    light.color = _LightColor.rgb * shadowAttenuation;         // 把陰影應用到光照顔色中
    return light;
} 
           

繼續閱讀