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

文章目录

  • 观察生活中的雾
    • 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 - 线性的

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第1张图片

Exponential - 指数的

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第2张图片

Exponential Squared - 指数平方的

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第3张图片

再参考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 < 30) || defined(SHADER_API_MOBILE)
        // mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color
        #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x)
    #else
        // SM3.0 and PC/console: calculate fog factor and lerp fog color
        #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR((coord).x); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)
    #endif
    #define UNITY_EXTRACT_FOG(name) float _unity_fogCoord = name.fogCoord
    #define UNITY_EXTRACT_FOG_FROM_TSPACE(name) float _unity_fogCoord = name.tSpace2.y
    #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name) float _unity_fogCoord = name.worldPos.w
    #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name) float _unity_fogCoord = name.eyeVec.w
#else
    #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)
    #define UNITY_EXTRACT_FOG(name)
    #define UNITY_EXTRACT_FOG_FROM_TSPACE(name)
    #define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name)
    #define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name)
#endif

这里就是最终应用个三计算出 FogFactor 公式,并将 FogFactor 作为 col, fogColor来插值。

下面我看

看看Linear/Exponential/Exponential Squared三个公式

从Unity Built-in shader 的代码中,可以看到三个公式的代码:

#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

Linear

L i n e a r = d m a x − z d m a x − d m i n e Linear=\frac{d_{max}-z}{d_{max}-d_{mine}} Linear=dmaxdminedmaxz

  • z z z:是片段ClipSpace下的z,但是我们可以用world space下的 length(_CameraWorldPos - FragWorldPos) 来替代或是view space下的z值都可以,因为这样再后续我们使用深度来重建世界坐标的方式会更方便
  • d m i n d_{min} dmin:就是下图的Start
  • d m a x d_{max} dmax:就是下图的End

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第4张图片

Exponential

E x p o n e n t i a l = f = e − d ⋅ z Exponential=f=e^{-d\cdot z} Exponential=f=edz

  • e e e 就是自然常数。
  • d d d:是雾的浓度,如下图的Density
  • z z z:同上 Linear

注意 − d ⋅ z -d\cdot z dz e e e的幂。
在CG函数刚好有一个:exp(a)的函数就表示: e a e^a ea

所以我们在shader里使用这个exp函数即可
Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第5张图片

Exponential Squared

E x p o n e n t i a l   S q u a r e d = f = e − ( d z ) 2 Exponential\space Squared=f=e^{-(dz)^2} Exponential Squared=f=e(dz)2

  • e e e:同上Exponential
  • d d d:和之前一样还是浓度,如下图
  • z z z:同上 Linear
    Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第6张图片

总结Unity 内置雾

优点

这种方式是很方便学习用的。
可以对半透明物体应用雾的效果,因为他可以对每一个渲染的对象shader处理。

缺点

这种方式性能没有后效的雾好。
而且必须要在每个shader添加代码来实现,实在是麻烦。
因为如果没有Early-z的话,很多看不见的片段有可能都执行了一次frag的fog代码,那就白白浪费性能了。

所以我们下面实现的是后效雾,使用后效的方式来实现

后效雾实现

这些后效雾,基本上都是需要:深度转世界坐标的,相关内容可以参考我之前的一篇:Unity Shader - 根据片段深度重建片段的世界坐标

后效雾我们可以两种来实现:深度雾高度雾

深度雾

就是所有像素都用深度来控制雾

shader

// jave.lin 2020.04.17 - 深度雾 - 代码写法很多可以优化,这里做学习用,便于高可读性
Shader "Custom/DepthFog" {
    Properties {
        [KeywordEnum(VIEWSPACE,WORLDSPACE)] _DIST_TYPE ("Distance type", int) = 0
        [KeywordEnum(LINEAR,EXP,EXP2)] _FUNC_TYPE ("Calculate Func type", int) = 0
        _MainTex ("Texture", 2D) = "white" {}

        _FogColor ("Fog Color", Color) = (0.5, 0.5, 0.5, 1)

        _Start ("Start", Float) = 0
        _End ("End", Float) = 100

        _Density ("Density", Range(0, 1)) = 0.3
    }
    SubShader {
        ZWrite Off ZTest Always Cull Off
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _DIST_TYPE_VIEWSPACE _DIST_TYPE_WORLDSPACE
            #pragma multi_compile _FUNC_TYPE_LINEAR _FUNC_TYPE_EXP _FUNC_TYPE_EXP2
            #include "UnityCG.cginc"
            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                uint id : SV_VertexID;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 ray : TEXCOORD1;
            };
            sampler2D _CameraDepthTexture;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _FogColor;
            float4x4 _Ray;
            float _Start;
            float _End;
            float _Density;
            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.ray = _Ray[v.id].xyz;
                return o;
            }
            fixed4 frag (v2f i) : SV_Target {

                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
                // return depth;

                // 下面的dist就是我们博客文章中公式的z
                float dist = 0;
                // dist:depth to world pos
                #if _DIST_TYPE_VIEWSPACE
                // 以view space .z
                float eyeZ = LinearEyeDepth(depth);
                dist = eyeZ;
                
                #else // _DIST_TYPE_WORLDSPACE
                // dist:以world space distance
                float linear01depth = Linear01Depth(depth);
                // float3 wp = _WorldSpaceCameraPos.xyz + i.ray * linear01depth;
                dist = length(i.ray * linear01depth);

                #endif

                float factor = 0;
                #if _FUNC_TYPE_LINEAR
                // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
                factor = (_End - dist) / (_End - _Start);
                
                #elif _FUNC_TYPE_EXP
                // factor = exp(-density*z)
                factor = exp(-(_Density * dist));

                #else // _FUNC_TYPE_EXP
                // factor = exp(-(density*z)^2)
                factor = exp(-pow(_Density * dist, 2));

                #endif

                factor = saturate(factor);

                return lerp(_FogColor, tex2D(_MainTex, i.uv), factor);
            }
            ENDCG
        }
    }
}

运行效果

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第7张图片

view space与world space的区别

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第8张图片

world space是以相机与片段的世界坐标距离来控制的

view space是以相机与片段的视角坐标的z距离来控制的

添加噪点

                // move the noise fog
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * Linear01Depth(depth);
                float noise = tex2D(_NoiseTex, wp.xz * _WorldPosScale + _Time.x * fixed2(_NoiseSpX, _NoiseSpY)).r * _NoiseScale;

                factor *= noise;

                factor = saturate(factor);

                return lerp(_FogColor, tex2D(_MainTex, i.uv), lerp(1, factor, _WholeIntensity));

OK,深度雾,基本先讲到这里,下面我们就看一下高度雾吧。

高度雾

如前面介绍所说,用高度控制,我们用两个参数:开始的高度,结束的高度。

Shader如下

// jave.lin 2020.04.17 - 高度雾 - 代码写法很多可以优化,这里做学习用,便于高可读性
Shader "Custom/HeightFog" {
    Properties {
        [KeywordEnum(VIEWSPACE,WORLDSPACE)] _DIST_TYPE ("Distance type", int) = 0
        [KeywordEnum(LINEAR,EXP,EXP2)] _FUNC_TYPE ("Calculate Func type", int) = 0
        _MainTex ("Texture", 2D) = "white" {}                                       // source tex
        _NoiseTex ("NoiseTex", 2D) = "white" {}                                     // 噪点图

        _FogColor ("Fog Color", Color) = (0.5, 0.5, 0.5, 1)                         // 雾的颜色

        _WorldPosScale ("WorldPosScale", Range(0, 0.1)) = 0.05                      // 世界坐标XY采样noiseTex的UV缩放值
        _NoiseSpX ("Noise Speed X", Range(0, 1)) = 1                                // 噪点滚动的速度(类似风吹动雾的效果)
        _NoiseSpY ("Noise Speed Y", Range(0, 1)) = 1                                // 噪点滚动的速度(类似风吹动雾的效果)

        _HeightStart ("Height Start", Float) = 1                                    // 淡入雾效的开始高度
        _HeightEnd ("Height End", Float) = 0                                        // 完全雾效的结束高度
        _HeightNoiseScale ("Height Noise Scale", Range(0, 10)) = 1                  // 高度噪点强度缩放

        _WholeIntensity ("WholeIntensity", Range(0, 1)) = 1                         // 整体效果的强度
    }
    SubShader {
        ZWrite Off ZTest Always Cull Off
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _DIST_TYPE_VIEWSPACE _DIST_TYPE_WORLDSPACE
            #pragma multi_compile _FUNC_TYPE_LINEAR _FUNC_TYPE_EXP _FUNC_TYPE_EXP2
            #include "UnityCG.cginc"
            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                uint id : SV_VertexID;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 ray : TEXCOORD1;
            };
            sampler2D _CameraDepthTexture;
            sampler2D _MainTex;
            sampler2D _NoiseTex;
            fixed4 _FogColor;
            float4x4 _Ray;
            float _WorldPosScale;
            float _NoiseSpX;
            float _NoiseSpY;
            float _HeightStart;
            float _HeightEnd;
            float _HeightNoiseScale;
            float _WholeIntensity;
            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.ray = _Ray[v.id].xyz;
                return o;
            }
            fixed4 frag (v2f i) : SV_Target {

                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
                // return depth;

                // world pos
                float3 wp = _WorldSpaceCameraPos.xyz + i.ray * Linear01Depth(depth);

                // move the noise fog
                float noise = tex2D(_NoiseTex, wp.xz * _WorldPosScale + _Time.x * fixed2(_NoiseSpX, _NoiseSpY)).r;
                float heightNoise = noise * _HeightNoiseScale;

                // height fog
                float factor = (_HeightEnd - wp.y - heightNoise) / (_HeightEnd - _HeightStart);

                factor = saturate(factor);

                fixed4 texCol = tex2D(_MainTex, i.uv);
                fixed4 fogColor = lerp(texCol, _FogColor, _FogColor.a);
                return lerp(fogColor, texCol, lerp(1, factor, _WholeIntensity));
            }
            ENDCG
        }
    }
}

运行效果

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第9张图片

添加噪点

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第10张图片

但是效果还是太单薄了写,没有深度感确实效果不太好,所以我们可以把:深度+高度混合,制作:深度高度雾

深度高度雾

Unity Shader PostProcessing - 11 - 雾效/深度雾效/高度雾/深度+高度雾_第11张图片

总结

雾的实现方式也是多种多样的,按具体需求来定。

还有一些是使用RayMarching的方式来实现的(RayMarching我还没有学习)。

吐槽一下,虽然CLike的语言都有很强大的Macro 宏定义,GLSL,HLSL,CG,还有我们的ShaderLab都有宏,但是宏的可读性真的极差无比。。。

Project

backup : UnityShader_Fog_2018.3.0f2

References

  • 《Unity Shader 入门精要》- 13.3
  • 《Unity Shader 入门精要》- 15.3

你可能感兴趣的:(unity,unity-shader)