#游戏unity-VR场景漫游#Unity中的雾效模拟

这一篇博客主要介绍如何实现shader中的雾效模拟特效。
其实在unity中有相关的组件,可以开启全局雾状特效,在Edit->Render Settings里配置如图——
这里写图片描述
上图包含了一些设置:雾的颜色,模拟雾采用的方法,雾的浓度(只在采用指数方法时有用),受雾影响的距离起点和终点(只在采用线性方法时有效)。其中,比较重要的是模拟雾采用的方法,即“Fog Mode”这一选项。它可以选择三种方法:
这里写图片描述

三种模式

Linear、Exponential和Exp2这三种模式实际上是使用了不同的公式计算雾的影响因子。这个影响因子会作为混合雾的颜色和物体原始颜色的参数,来计算最终的混合颜色。
如果影响因子为1,则表明完全没有雾效;如果为0,则表示完全被雾覆盖。而三种模式使用的公式分别如下所示:

  • Linear
    这里写图片描述
    其中Dmax和Dmin分别表示受雾影响的距离起点和终点。

  • Exponential
    这里写图片描述
    其中d表示雾的浓度。

  • Exp2
    这里写图片描述
    三个等式中的z,表示距离摄像机的远近。

以上三种模式的效果图,如下所示——
原始图片——
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
它们的雾效配置如下所示:
这里写图片描述

内部原理实现

1.在Properties块中添加雾效的几个设置参数:

Properties {  
       _MainTex ("Base (RGB)", 2D) = "white" {}  
       _Ramp ("Ramp Texture", 2D) = "white" {}  
       _Tooniness ("Tooniness", Range(0.1,20)) = 4  
       _Outline ("Outline", Range(0,1)) = 0.1  

       _FogColor("Fog Color", Color) = (1, 0, 0, 0)  
       _FogIntensity("Fog Intensity", float) = 0.1  
       _FogStart("Fog Start", float) = 0  
       _FogEnd("Fog End", float) = 300  
   }  

2.添加模拟雾效的函数:

float4 SimulateFog(float4 pos, float4 col)  
        {  
            pos.w = 0.0;  
            float dist = length(pos);  
//          float dist = pos.z;  
            // Linear  
//          float fogFactor = (_FogEnd - abs(dist)) / (_FogEnd - _FogStart);  
//          fogFactor = clamp(fogFactor, 0.0, 1.0);  

            // Exponential  
//          float fogFactor = exp(-abs(_FogIntensity * dist));  
//          fogFactor = clamp(fogFactor, 0.0, 1.0);  

            // Exp2  
            float fogFactor = exp(-(_FogIntensity * dist) * (_FogIntensity * dist));  
            fogFactor = clamp(fogFactor, 0.0, 1.0);  

            float3 afterFog = mix(_FogColor.rgb, col.rgb, fogFactor);  

            return float4(afterFog, col.a);  
        }  

以上,函数参数pos是指在view space中顶点的位置,因为只有在这个坐标系中,摄像机的位置总是位于原点。在计算距离摄像机远近时,我们有两种可选方式:一种直接使用pos.z得到近似值,一种是使用真正距离摄像机的距离,即计算xyz平方和后开根号的结果。第二种方法由于使用了计算根号这种操作,因此在性能上略微比第一种查一点,但效果也更真实。

源码

Shader "Custom/FogSimulation" {  
    Properties {  
        _MainTex ("Base (RGB)", 2D) = "white" {}  
        _Ramp ("Ramp Texture", 2D) = "white" {}  
        _Tooniness ("Tooniness", Range(0.1,20)) = 4  
        _Outline ("Outline", Range(0,1)) = 0.1  

        _FogColor("Fog Color", Color) = (1, 0, 0, 0)  
        _FogIntensity("Fog Intensity", float) = 0.1  
        _FogStart("Fog Start", float) = 0  
        _FogEnd("Fog End", float) = 300  
    }  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
        LOD 200  

        CGINCLUDE  
        #include "UnityCG.cginc"   

        sampler2D _MainTex;  
        sampler2D _Ramp;  

        float4 _MainTex_ST;  

        float _Tooniness;  
        float _Outline;  

        float4 _FogColor;  
        float _FogIntensity;  
        float _FogStart;  
        float _FogEnd;  

        float4 SimulateFog(float4 pos, float4 col)  
        {  
            pos.w = 0.0;  
            float dist = length(pos);  
//          float dist = pos.z;  
            // Linear  
//          float fogFactor = (_FogEnd - abs(dist)) / (_FogEnd - _FogStart);  
//          fogFactor = clamp(fogFactor, 0.0, 1.0);  

            // Exponential  
//          float fogFactor = exp(-abs(_FogIntensity * dist));  
//          fogFactor = clamp(fogFactor, 0.0, 1.0);  

            // Exp2  
            float fogFactor = exp(-(_FogIntensity * dist) * (_FogIntensity * dist));  
            fogFactor = clamp(fogFactor, 0.0, 1.0);  

            float3 afterFog = mix(_FogColor.rgb, col.rgb, fogFactor);  

            return float4(afterFog, col.a);  
        }  

        ENDCG  

        Pass {  
            Tags { "LightMode"="ForwardBase" }  

            Cull Front  
            Lighting Off  
            ZWrite On  

            CGPROGRAM  

            #pragma vertex vert  
            #pragma fragment frag  

            #pragma multi_compile_fwdbase  

            #include "UnityCG.cginc"  

            struct a2v  
            {  
                float4 vertex : POSITION;  
                float3 normal : NORMAL;  
            };   

            struct v2f  
            {  
                float4 pos : POSITION;  
                float4 viewSpacePos : TEXCOORD0;  
            };  

            v2f vert (a2v v)  
            {  
                v2f o;  

                float4 pos = mul( UNITY_MATRIX_MV, v.vertex);   
                float3 normal = mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal);    
                normal.z = -0.5;  
                pos = pos + float4(normalize(normal),0) * _Outline;  
                o.pos = mul(UNITY_MATRIX_P, pos);  

                o.viewSpacePos = mul( UNITY_MATRIX_MV, v.vertex);  

                return o;  
            }  

            float4 frag(v2f i) : COLOR    
            {   
                return SimulateFog(i.viewSpacePos, float4(0, 0, 0, 1));                 
            }   

            ENDCG  
        }  

        Pass {  
            Tags { "LightMode"="ForwardBase" }  

            Cull Back   
            Lighting On  

            CGPROGRAM  

            #pragma vertex vert  
            #pragma fragment frag  

            #pragma multi_compile_fwdbase  

            #include "UnityCG.cginc"  
            #include "Lighting.cginc"  
            #include "AutoLight.cginc"  
            #include "UnityShaderVariables.cginc"  

            struct a2v  
            {  
                float4 vertex : POSITION;  
                float3 normal : NORMAL;  
                float4 texcoord : TEXCOORD0;  
                float4 tangent : TANGENT;  
            };   

            struct v2f  
            {  
                float4 pos : POSITION;  
                float2 uv : TEXCOORD0;  
                float3 normal : TEXCOORD1;  
                float4 viewSpacePos : TEXCOORD2;  
                LIGHTING_COORDS(3,4)  
            };  

            v2f vert (a2v v)  
            {  
                v2f o;  

                //Transform the vertex to projection space  
                o.pos = mul( UNITY_MATRIX_MVP, v.vertex);   
                o.normal  = mul((float3x3)_Object2World, SCALED_NORMAL);  
                //Get the UV coordinates  
                o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);    

                o.viewSpacePos = mul( UNITY_MATRIX_MV, v.vertex);  

                // pass lighting information to pixel shader  
                TRANSFER_VERTEX_TO_FRAGMENT(o);  
                return o;  
            }  

            float4 frag(v2f i) : COLOR    
            {   
                //Get the color of the pixel from the texture  
                float4 c = tex2D (_MainTex, i.uv);    
                //Merge the colours  
                c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness);  

                //Based on the ambient light  
                float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz;  

                //Work out this distance of the light  
                float atten = LIGHT_ATTENUATION(i);  
                //Angle to the light  
                float diff =  dot (normalize(i.normal), normalize(_WorldSpaceLightPos0.xyz));    
                diff = diff * 0.5 + 0.5;   
                //Perform our toon light mapping   
                diff = tex2D(_Ramp, float2(diff, 0.5));  
                //Update the colour  
                lightColor += _LightColor0.rgb * (diff * atten);   
                //Product the final color  
                c.rgb = lightColor * c.rgb * 2;  

                return SimulateFog(i.viewSpacePos, c);  
            }   

            ENDCG  
        }  
    }  
    FallBack "Diffuse"        
}  

猜你喜欢

转载自blog.csdn.net/zys91011_muse/article/details/80301003