Lighting Box2原始碼分析(四):Global Fog全域性霧
LB全域性霧分距離霧和高度霧兩部分計算
距離霧
//傳入相機位置指向當前點方向,深度 // Distance-based fog float ComputeDistance (float3 camDir, float zdepth) { float dist; //是否使用半徑深度 if (_SceneFogMode.y == 1) //是的話返回當前點到相機的距離 dist = length(camDir); else //否則返回z深度*遠平面=世界空間深度值 //_ProjectionParams:x is 1.0 (or –1.0 if currently rendering with a flipped projection matrix), y is the camera’s near plane, z is the camera’s far plane and w is 1/FarPlane. dist = zdepth * _ProjectionParams.z; //-近平面=到相機的距離 dist -= _ProjectionParams.y; return dist; }
有兩種距離,第一種是當前點位置到相機位置距離,第二種是隻把Z深度作為距離
高度霧
高度霧演算法為 ofollow,noindex" target="_blank">這篇文章中的演算法
//傳入世界空間視角方向 float ComputeHalfSpace (float3 wsDir) { //世界空間位置 float3 wpos = _CameraWS + wsDir; //霧結束高度 float FH = _HeightParams.x; //相機世界位置 float3 C = _CameraWS; //世界空間視角方向 float3 V = wsDir; //世界空間位置 float3 P = wpos; //av = 世界空間視角方向*密度引數 float3 aV = _HeightParams.w * V; //相機到高度引數的距離,,表示相機的高度霧濃度,<0在霧中,越小霧越濃 float FdotC = _HeightParams.y; //相機在高度霧中k = 1,相機在霧上面k = 0 float k = _HeightParams.z; //當前點到霧結束位置的高度,,表示當前位置的的高度霧濃度,<0在霧中,越小霧越濃 float FdotP = P.y-FH; //相機到當前點的高度 float FdotV = wsDir.y; //相機在高度霧中c1 = 當前位置的的高度霧濃度+相機的高度霧濃度,相機在霧上面c1 = 0 float c1 = k * (FdotP + FdotC); //相機在高度霧中c2 = -當前位置的的高度霧濃度,相機在霧上面c2 = 當前位置的的高度霧濃度 float c2 = (1-2*k) * FdotP; //獲得當前位置的的高度霧濃度 float g = min(c2, 0.0); g = -length(aV) * (c1 - g * g / abs(FdotV+1.0e-5f)); return g; }
高度霧受根據物體與相機距離影響,離得越近霧濃度越低
給出一個高度平面(高度就可以,法向量預設向上),在平面之下受霧影響,在平面之上不受霧影響
F為霧平面法線,F·P用來判斷P點是在霧平面之上還是之下,在LightingBox中,直接傳入高度值,將世界空間高度值與當前世界空間位置的Y作比較來判斷二者關係
這樣就有四種情況需要考慮,下圖P為當前點,C為相機點
第一種情況圖a中P和C都在霧平面上面,所以P是不受霧影響的,
第二種情況需要考慮CP連線與霧平面有交點的情況,V為視角方向V = C-P,當F·V和F·C符號不同時,說明有交點,可計算出交點位置,假設交點位置為Q(t)
Line"/>
如果F·C>0說明相機在霧平面上,當前點在霧平面下,所求霧濃度為t||V||
如果F·C<0說明相機在霧平面下,當前點在霧平面上,所求霧濃度為(1-t)||V||
為了避免過多條件判斷影響效能,將公式變為
接下來加入線性密度的計算,下圖ac為恆定密度,db為線性密度
ρ (P)為所求線性密度,將剛才求得的高度結果*線性密度
接下來又通過積分的方式取代 ρ (P),上面abcd四種結果得到的
再將四種化為一種公式,得到最終結果
混合結果
混合距離和高度結果
half4 ComputeFog (v2f i, bool distance, bool height) : SV_Target { half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv); float rawDepth = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,i.uv); float dpth = Linear01Depth(rawDepth); //世界空間視角方向 float4 wsDir = dpth * i.interpolatedRay; //世界空間位置 float4 wsPos = _CameraWS + wsDir; //霧開始距離startDistance float g = _DistanceParams.x; if (distance) //+=當前點到相機的距離 g += ComputeDistance (wsDir, dpth); if (height) //+=高度 g += ComputeHalfSpace (wsDir); //三種霧演算法 half fogFac = ComputeFogFactor (max(0.0,g)); //最遠處(天空盒)是否有霧 rawDepth == 1為最遠 if (rawDepth == _DistanceParams.y) fogFac = 1.0; //混合霧顏色 return lerp (unity_FogColor, sceneColor, fogFac); }
三種霧模式
half ComputeFogFactor (float coord) { float fogFac = 0.0; if (_SceneFogMode.x == 1) // linear { //深度|高度*-場景長度 + 最遠點 fogFac = coord * _SceneFogParams.z + _SceneFogParams.w; } if (_SceneFogMode.x == 2) // exp { //exp2(深度|高度*密度/sqrt(ln2)) fogFac = _SceneFogParams.y * coord; fogFac = exp2(-fogFac); } if (_SceneFogMode.x == 3) // exp2 { //exp2(深度|高度*密度/ln2) fogFac = _SceneFogParams.x * coord; fogFac = exp2(-fogFac*fogFac); } return saturate(fogFac); }