unity3d 的 UNITY_CALC_FOG_FACTOR_RAW 宏 -- 雾效果计算

作用:

根据片元到摄像机的距离得到雾的浓度

用法:

定义关键字,

#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.csdn.net/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

三种情况的雾浓度计算(线性、指数、指数平方)

线性:

图片

指数:

图片

指数平方:
图片

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值