作用:
根据片元到摄像机的距离得到雾的浓度
用法:
定义关键字,
#pragma multi_compile_fog
相当于#pragma multi_compile FOG_LINEAR FOG_EXP FOG_EXP2 ,三个分别对于对应Lighting Window - Other Setting - Fog - Mode里面的三个选项(线性、指数、指数平方)。
第一种做法,利用片元到摄像机的距离来计算雾浓度:
// 得到和雾效混合后的颜色
float4 ApplyFog(float4 color, Interpolators i)
{
float viewDistance = length(_WorldSpaceCameraPos - i.worldPos); // 片元与摄像机的距离
UNITY_CALC_FOG_FACTOR_RAW(viewDistance); // 计算雾浓度
color.rgb = lerp(unity_FogColor.rgb, color.rgb, saturate(unityFogFactor)); // 根据雾浓度在片元颜色与雾颜色之间插值
return color
}
另一种做法,利用裁剪空间下的z值(深度)进行雾浓度计算,这也是unity built-in shader里的做法
// 片元输入结构
struct Interpolators{
...
// 如果用深度算雾浓度
#if FOG_DEPTH
float4 worldPos : TEXCOORD4; // 把裁剪空间坐标的z值存到w里,不直接用i.pos是因为SV_POSITION语义下,裁剪坐标传到了片元函数之后会改变,这里用另外的变量来存
#else
float3 worldPos; // 正常的世界坐标,只有三个分量
#endif
...
}
Interpolators MyVertexProgram(appdata v){
Interpolators i;
i.pos = UnityObjectToClipPos(v.vertex);
i.worldPos.xyz = mul(unity_ObjectToWorld, v.vertex);
#if FOG_DEPTH
i.worldPos.w = i.pos.z; // 把深度存进去
#endif
...
}
float4 ApplyFog(float4 color, Interpolators i){
float viewDistance = length(_WorldSpaceCameraPos - i.worldPos.xyz);
#if FOG_DEPTH
// 用裁剪坐标的z值作为距离后面计算雾浓度,这里调用UNITY_Z_0_FAR_FROM_CLIPSPACE把不同平台的裁剪坐标z轴映射到[0 , 1]的范围
// 解析:https://blog.youkuaiyun.com/zengjunjie59/article/details/112526420
viewDistance = UNITY_Z_0_FAR_FROM_CLIPSPACE(i.worldPos.w);
#endif
UNITY_CALC_FOG_FACTOR_RAW(viewDistance); // 计算雾浓度
color.rgb = lerp(unity_FogColor.rgb, color.rgb, saturate(unityFogFactor));
return color;
}
FragmentOutPut MyFragmentProgram(Interpolators i){
...
output.color = ApplyFog(color, i);
return output;
}
源码:
#if defined(FOG_LINEAR)
// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
#elif defined(FOG_EXP)
// factor = exp(-density*z)
#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
#elif defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor)
#else
#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0
#endif
三种情况的雾浓度计算(线性、指数、指数平方)
线性:
指数:
指数平方: