這兩個方法用于計算陰影漸變衰減
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為例:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSP9E1TxU1VhFXNXRWck1mYsB3MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4UTM3QjNzYTMxITMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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;
}