Unity 内置雾

缺点:要为场景中所有物体的 shader 添加代码,实现的效果有限。

全局雾效

基于屏幕后处理的全局雾效,不需要改 shader 代码。自由度很高

关键:根据深度图来重建每个像素在世界空间下的位置。

在简单的雾效实现中,我们需要计算一个雾效系数$f$,作为混合原始颜色和雾的颜色的混合系数;
这个雾效系数 $f$ 有很多计算方法。在 Unity 内置的雾效实现中,支持三种雾的计算方式——线性(Linear)、指数(Exponential)以及指数的平方(Exponential Squared)。

当给定距离 $z$ 后,$f$ 的计算公式分别如下:

  • Linear:$d_{min}$ 和 $d_{max}$ 分别表示受雾影响的最小距离和最大距离
    $$
    f=\frac{d_{max}-\mid z\mid}{d_{max}-d_{min}}
    $$
  • Exponential:$d$ 是控制雾的浓度的参数
    $$
    f=e^{-d\cdot|z|}
    $$
  • Exponential Squared:$d$ 是控制雾的浓度的参数
    $$
    f=e^{-(d-|z|)^2}
    $$

基于高度的雾效

本节使用线性雾来计算:
当给定一点在世界空间下的高度 $y$ 后,$f$ 的计算公式为:
$$
f=\frac{H_{end}-y}{H_{end}-H_{start}}
$$
$H_{far}$, 和 $H_{end}$ 分别表示受雾影响的起始高度和终止高度

h:16,19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//1 用深度纹理和屏幕空间uv重建像素的世界空间位置
//屏幕空间uv
float2 ScreenUV = i.positionCS.xy / _ScaledScreenParams.xy;
//从深度纹理中采样深度
#if UNITY_REVERSED_Z
// 具有 REVERSED_Z 的平台(如 D3D)的情况。
//返回[1,0]的深度值
real depth = SampleSceneDepth(ScreenUV);
#else
// 没有 REVERSED_Z 的平台(如 OpenGL)的情况。
// 调整 Z 以匹配 OpenGL 的 NDC([-1, 1])
real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(ScreenUV));
#endif

// 重建世界空间位置
float3 rebuildPosWS = ComputeWorldSpacePosition(ScreenUV, depth, UNITY_MATRIX_I_VP);

//2 计算雾
float fogDensity = (_FogEnd-rebuildPosWS.y)/(_FogEnd-_FogStart);
fogDensity = saturate(fogDensity*_FogDensity);
float4 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_BlitTexture, i.uv);
color.rgb = lerp(color.rgb, _FogColor, fogDensity);

基于深度的雾效

h:9,12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//采样深度图,转换为线性深度
float2 ScreenUV = i.positionCS.xy / _ScaledScreenParams.xy;
#if UNITY_REVERSED_Z
float depth = SampleSceneDepth(ScreenUV);
#else
float depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(ScreenUV));
#endif

float linearDepth = LinearEyeDepth(depth, _ZBufferParams);

//计算雾的密度
float fogDensity = (linearDepth-_FogStart)/(_FogEnd-_FogStart);
fogDensity = saturate(fogDensity*_FogDensity);
float4 color = SAMPLE_TEXTURE2D(_BlitTexture, sampler_BlitTexture, i.uv);
color.rgb = lerp(color.rgb, _FogColor, fogDensity);

return color;