US4L8-5——噪声雾效
US4L8-5——噪声雾效
噪声雾效
因此所谓的噪声雾效,其实就是在我们之前已经实现的屏幕后处理效果中的全局雾效中,
结合噪声和内置时间参数,去实现出不规则、动态的全局雾效,让我们的雾效更具动态感,真实感!
实现的全局雾效相关内容可见:US3S11L6——深度纹理实现全局雾效
噪声雾效基本原理
一句话总结噪声雾效基本原理:
噪声雾效可以基于我们之前实现的屏幕后处理效果的全局雾效进行修改,通过添加噪声纹理结合 Shader 内置时间变量实现雾的不均匀以及动态效果
关键点:
-
不均匀效果的实现
我们可以利用柏林噪声算法生成的噪声纹理灰度图来制作不均匀感。
从灰度图中采样得到 0~1 范围的值,再通过减去 0.5 的方式将其区间变为 -0.5~0.5 之间,
并用这个系数参与最后的雾的混合因子计算中,从而让均匀的雾变得不均匀。
1
2
3
4
5
6float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed); // 雾的动态计算
float noise = (tex2D(_Noise, i.uv + speed).r - 0.5) * _NoiseAmount; // 把原本0~1的采样变化到-0.5~0.5,再乘以噪声系数,用于控制正负范围
// ...
float f = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); // 混合因子的计算
// 取0~1之间,超过取极值,然后用该噪声系数参与到最终的雾的混合因子计算中,让雾的密度产生正负方向的动态扰动
f = saturate(f * _FogDensity * (1 + noise)); -
动态效果的实现
类似水波效果,自定义 x 轴和 y 轴的两个速度变量。利用 Shader 内置时间参数
_Time.y
得到累积变化。
用该速度变量从噪声纹理中偏移采样,从而达到动态效果。1
2
3
4
5
6float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed); // 雾的动态计算
float noise = (tex2D(_Noise, i.uv + speed).r - 0.5) * _NoiseAmount; // 把原本0~1的采样变化到-0.5~0.5,再乘以噪声系数,用于控制正负范围
// ...
float f = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); // 混合因子的计算
// 取0~1之间,超过取极值,然后用该噪声系数参与到最终的雾的混合因子计算中,让雾的密度产生正负方向的动态扰动
f = saturate(f * _FogDensity * (1 + noise));
噪声雾效 Shader 实现
-
新建 Shader,命名为
NoiseFog
,复制屏幕后处理效果的全局雾效Shader代码详见:US3S11L6——深度纹理实现全局雾效
-
修改 Shader 代码
-
属性添加
- 噪声纹理
_Noise
- 噪声值偏移系数
_NoiseAmount
- X 轴移动速度
_FogXSpeed
- Y 轴移动速度
_FogYSpeed
属性映射
1
2
3
4
5
6
7
8
9
10
11
12Properties
{
_MainTex("Texture", 2D) = "white"{}
_FogColor("FogColor", Color) = (1, 1, 1, 1) // 雾的颜色
_FogDensity("FogDensity", Float) = 1 // 雾的浓度
_FogStart("FogStart", Float) = 0 // 雾开始的距离
_FogEnd("FogEnd", Float) = 10 // 雾最浓时的距离
_Noise("Noise", 2D) = ""{} // 噪声纹理
_NoiseAmount("NoiseAmount", Float) = 1 // 噪声值偏移系数
_FogXSpeed("FogXSpeed", Float) = 0.1 // X轴移动速度
_FogYSpeed("FogYSpeed", Float) = 0.1 // Y轴移动速度
} - 噪声纹理
-
片元着色器修改
-
速度计算,噪声纹理偏移采样,从 0~1 范围转到 -0.5~0.5 范围,再乘以
_NoiseAmount
噪声系数,用于控制正负范围1
2
3
4// 计算噪声图采样偏移,把原本0~1的噪声范围值变化到-0.5~0.5,再乘以_NoiseAmount噪声系数,用于控制正负范围
float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed);
float noise = (tex2D(_Noise, i.uv + speed).r - 0.5) * _NoiseAmount; -
参与雾混合因子计算
1
2// 乘以1 + noise是为了在正常计算出来的混合因子动进行上下的扰动
f = saturate(f * _FogDensity * (1 + noise)); // 乘以雾的浓度,取0~1之间,超过则取极值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18fixed4 frag (v2f i) : SV_Target
{
// 获取观察空间下离摄像机的实际距离(Z分量)并计算世界空间下的像素坐标
float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.ray;
// 计算噪声图采样偏移,把原本0~1的噪声范围值变化到-0.5~0.5,在乘以_NoiseAmount噪声系数,用于控制正负范围
float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed);
float noise = (tex2D(_Noise, i.uv + speed).r - 0.5) * _NoiseAmount;
// 雾相关的计算,可以根据自己需求修改计算方法,这里是基于高度的全局雾效
float f = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); // 使用世界空间的像素坐标高度计算混合因子
// 乘以1 + noise是为了在正常计算出来的混合因子动进行上下的扰动
f = saturate(f * _FogDensity * (1 + noise)); // 乘以雾的浓度,取0~1之间,超过则取极值
// 利用插值,在两个颜色之间进行融合
fixed3 color = lerp(tex2D(_MainTex, i.uv).rgb, _FogColor.rgb, f);
return fixed4(color.rgb, 1);
} -
-
噪声雾效 C# 实现
-
新建 C# 代码
NoiseFog
-
复用屏幕后处理效果的全局雾效 C# 代码
FogWithDepthTexture
代码详见:US3S11L6——深度纹理实现全局雾效
-
修改 C# 代码
-
添加成员变量
纹理、系数、速度
-
设置 Shader 参数
-
1 | using UnityEngine; |
显示效果
噪声值偏移系数为1,X轴和Y轴移动速度都为0.1
可见,雾效呈现出来一种不均匀的,飘动的效果,雾的效果更接近于现实中的团雾了