您当前的位置: 首页 >  unity

Jave.Lin

暂无认证

  • 1浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader PostProcessing - 11 - Depth Fog/Height Fog - 雾效/深度雾效/高度雾/深度+高度雾

Jave.Lin 发布时间:2020-04-17 18:54:56 ,浏览量:1

文章目录
  • 观察生活中的雾
    • Scenario 1 - Pure Depth Fog - 纯深度雾
      • 提取有用信息
    • Scenario 2 - Height Fog - 带高度的雾
      • 提取有用信息
    • Scenario 1 & 2 are same - 本质上两种雾都是一样的
  • 先看看Unity自带的Fog效果
    • Linear - 线性的
    • Exponential - 指数的
    • Exponential Squared - 指数平方的
  • 再参考Unity Built-in shader的Fog部分
    • UnityCG.cginc Fog Helper 开始
    • sutrct v2f 中的 UNITY_FOG_COORDS
    • vert 函数中的 UNITY_TRANSFER_FOG
    • frag 函数中的 UNITY_APPLY_FOG
    • 看看Linear/Exponential/Exponential Squared三个公式
      • Linear
      • Exponential
      • Exponential Squared
    • 总结Unity 内置雾
    • 优点
    • 缺点
  • 后效雾实现
    • 深度雾
      • 运行效果
      • view space与world space的区别
      • 添加噪点
    • 高度雾
      • 添加噪点
    • 深度高度雾
  • 改进版本的高度雾
  • 总结
  • Project
  • References

观察生活中的雾

先不看效果,我们先细心想想,生活中看到的雾是怎么个表现?

Scenario 1 - Pure Depth Fog - 纯深度雾

不过现在基本上都看不到雾了,很多年没有见过,印象中的雾应该在8~9年前,那时候坐着大巴,司机开得很慢很慢,因为雾太浓了,雾的颜色比奶白色暗一些,眼前只有2~5M可视,再远一点就全是雾了。

所以我们确定了一些有用的信息: 雾的颜色,眼前2~5M可视,再远一点就全是雾了。

提取有用信息
  • 雾的颜色
  • 眼前 的眼,可以理解为我们的相机位置
  • 2~5M 可以看过是雾化淡入的范围
  • 再远一点全是雾
Scenario 2 - Height Fog - 带高度的雾

如:我们常常看到一些综艺节目里,或是音乐节目里整个舞台地表大概:0.2M都是雾。

提取有用信息

就是有高度

Scenario 1 & 2 are same - 本质上两种雾都是一样的

Scenario 1与2的两种雾起始都是一样的,为什么我们需要做两种区别能:分开实现,在不同场景使用性能更好。

当然你也可以使用Scenario 2中的雾来实现所有的场景,调整一下雾的高度为:很大的值(很高)即可。

我按照自己的理解就是:雾的固状体有密度区别。

密度低一些的雾就会飘得比较高,以至于高到我们整改眼前的视野都包括了,所以我们对这种雾处理为:纯深度雾。

密度高一些的雾就会飘得比较低,就像前面提到的舞台上的雾(一般是一些干冰雾),所以我们处理为:高度雾,只有部分高度可见。

上面只是我自己的理解,百度百科有比较全面的了解,有兴趣点击这里查看:雾

下面讲解以unity 2018.3.0f2 版本为主

先看看Unity自带的Fog效果 Linear - 线性的

在这里插入图片描述

Exponential - 指数的

在这里插入图片描述

Exponential Squared - 指数平方的

在这里插入图片描述

再参考Unity Built-in shader的Fog部分

我们在创建shader选择unlit shader就得到一个代码模板生成的shader

代码如下

Shader "Unlit/Fog"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

可以看到有各种 Fog的字眼。

那么下面我们接着看看这些宏对应Built-in Shader里有是什么内容 (这里只看一些主要的部分,不会全面的去看)

UnityCG.cginc Fog Helper 开始
// ------------------------------------------------------------------
//  Fog helpers
//
//  multi_compile_fog Will compile fog variants.
//  UNITY_FOG_COORDS(texcoordindex) Declares the fog data interpolator.
//  UNITY_TRANSFER_FOG(outputStruct,clipspacePos) Outputs fog data from the vertex shader.
//  UNITY_APPLY_FOG(fogData,col) Applies fog to color "col". Automatically applies black fog when in forward-additive pass.
//  Can also use UNITY_APPLY_FOG_COLOR to supply your own fog color.
  • multi_compile_fog 编译雾的变体shader的指令。
  • UNITY_FOG_COORDS(texcoordindex) 定义雾需要的v2f的插值数据。
  • UNITY_TRANSFER_FOG(outputStruct,clipspacePos)vertex shader顶点着色器输出数据
  • UNITY_APPLY_FOG(fogData,col) 应用雾的颜色来着色。当使用forward-additive lightmode的pass会自动应用黑色的雾颜色。
  • 也可以使用UNITY_APPLY_FOG_COLOR来当做是雾的颜色
sutrct v2f 中的 UNITY_FOG_COORDS
            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

UNITY_FOG_COORDS 对应UnityCG.cginc 下的源码

// 1
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
    #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)、

// 2
#define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx;

可以看到,就是定义一个float1 fogCoord : TEXCOORD[N]的一个变量。

vert 函数中的 UNITY_TRANSFER_FOG
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
// 1
#define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor

// 2
#if defined(UNITY_REVERSED_Z)
    #if UNITY_REVERSED_Z == 1
        //D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]
        //max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices.
        #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)
    #else
        //GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
        #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)
    #endif
#elif UNITY_UV_STARTS_AT_TOP
    //D3d without reversed z => z clip range is [0, far] -> nothing to do
    #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else
    //Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)
    #define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#endif

#define UNITY_CALC_FOG_FACTOR(coord) UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord))

// 3
#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

// 4
CBUFFER_START(UnityFog)
    fixed4 unity_FogColor;
    // x = density / sqrt(ln(2)), useful for Exp2 mode
    // y = density / ln(2), useful for Exp mode
    // z = -1/(end-start), useful for Linear mode
    // w = end/(end-start), useful for Linear mode
    float4 unity_FogParams;
CBUFFER_END

// 5
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane
// z = far plane
// w = 1/far plane
uniform vec4 _ProjectionParams;

可以看到一些有用的信息:

  • unity_FogParams:用于CPU将一些除法结果计算好传入到GPU的 CBuffer 中使用的,减少GPU中的除法运算,提升性能。
  • FOG_LINEARFOG_EXPFOG_EXP2分别对应了Unity中的Fog 算法的选择。从三个宏定义的分支可以知道三种算法对应的公式。

从这里也可以看得出来,unity的 Fog 使用的是 ClipSpace下的z值来计算FogFactor。

  • 先将ClipSpace.z 映射到0~far
  • 然后用上面0~farClipSpace.z来作为z代入对应公式计算unityFogFactor
  • 最后是下面的frag UNITY_APPLY_FOG应用这个unityFogFactorlerp(col, fragCol, untiyFogFactor)

从这里我们知道了三种公式,后面会继续说明

frag 函数中的 UNITY_APPLY_FOG
#ifdef UNITY_PASS_FORWARDADD
    #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
#else
    #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
#endif

这个可以看到,对应之前的 Helper 里说的,forward add的话,会使用黑色作为雾颜色

#define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))


#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
    #if (SHADER_TARGET             
关注
打赏
1664331872
查看更多评论
0.0464s