write in front
Knowing unity knows that unity can perform basic fog simulations. The so-called fog effect, is in the direction away from our perspective, the object appears to be covered with a certain color (usually gray). The implementation of this technique is actually very simple, which is to mix the color of the fog and the color of the object according to the distance of the object from the camera.
There are two ways to set fog in unity, the simplest of which is to directly turn on global fog , which is configured in Edit->render settings, as shown in:
And we just need to open the check box after the "Fog" option. Some settings are included: Fog color, Simulated fog method, fog concentration (only useful when using exponential method), start and end point of the distance affected by fog (only valid when linear method is used). Among them, it is more important to simulate fog using the method, namely "Fog Mode" this option. It can be selected in three ways:
Another way is to set it in shader with the Fog Directive . Here is a description of the official website.
three different modes
The three modes of Linear, exponential, and EXP2 are actually using different formulas to calculate the influence factor of fog. This effect factor calculates the final blend color as the color of the blend fog and the parameters of the object's original color. For example, we use the following statement to calculate:
FLOAT3 Afterfog = Mix (_fogcolor.rgb, Col.rgb, fogfactor);
If the impact factor is 1, it means that there is no fog effect at all, and if 0, it is completely covered by fog. The formulas used in the three modes are as follows:
- Linear:
, where DMax and DMin respectively represent the starting and ending points of the fog-affected distance.
- Exponential:
, where D indicates the concentration of fog.
- EXP2:
, where D indicates the concentration of fog.
The z in the three equations represents the distance from the camera.
In order to fully understand the principle of fog efficiency and the differences between the three methods, we will be in the fragment shader to simulate the fog effect.
Unity-Simulated fog effect
We use the following simple cartoon apple scene (Little Apple is really my favorite ...). ) to test the fog effect. The original scene:
The distance from the camera farthest to the small Apple is about 25 units.
After we opened Unity's global fog effect, we used three different methods to simulate it, and the results were as follows:
Their fog-effect configurations are as follows:
We will explain the meaning of these parameters later, and now we only need to know that "Fog Density" is only useful when "Fog Mode" is "exponential" or "EXP2", while "Linear Fog Start" and " Linear Fog End " is only useful when Fog Mode is" Linear ". Note that the above "Linear Fog Start" and "Linear Fog End" parameters are set based on the "distance from the camera farthest away from the small Apple, which is about 25 units", just to make the fog more obvious.
Now, we can visually understand the similarities and differences between the three methods.
internal principles of fog implementation
In order to fully understand the fog efficiency algorithm, we now add the fog algorithm to the existing shader of the small apple.
- First, we need to add a few setting parameters for the fog effect in the properties block:
properties {_maintex ("Base (RGB)", 2D) = "wh Ite "{} _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 intens ity ", float) = 0.1 _fogstart (" Fog Start ", float) = 0 _fogend (" Fog End ", float) = +}
-
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 (f Ogfactor, 0.0, 1.0);//Exponential//float Fogfactor = exp (-abs (_fogintensity * dist));//fogfactor = Clamp (fogfactor, 0.0, 1.0);//Exp2float 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);}
explanation : With the formula above, this function is well understood. It is worth noting that the function parameter Pos refers to the position of the vertex in the view space, because only in this coordinate system, the camera's position is always at the origin point. We have two options for calculating the distance from the camera: a direct use of the pos.z to get the approximate value, one is to use the distance from the actual camera, that is, the result of calculating the square of XYZ and the posterior open root. The second method, because of the use of the calculation of the square root of this operation, so slightly more performance than the first check, but the effect is more realistic.
the three modes that use the above code are as follows:
The use of the Apple body part of the fog shader, leaves and stems are not used oh ~ can be seen, and unity simulation effect is basically the same.
Finally, the complete code is as follows:
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 ("F OG Start ", float) = 0 _fogend (" Fog End ", float) = Subshader {Tags {" rendertype "=" Opaque "} LOD 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);//Exp2float 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 Oncgprogram#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:norma L;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 Spaceo.pos = Mul (UNITY_MATRIX_MVP, v.ve Rtex); O.normal = Mul ((float3x3) _Object2world, Scaled_normal);//get the UV coordinateso.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 texturefloat4 c = tex2d (_maintex, I.UV); Merge the Coloursc.rgb = (Floor (c.rgb*_tooniness)/_tooniness),//based on the ambient lightfloat3 lightcolor = Unity_lig Htmodel_ambient.xyz;//work out this distance of the lightfloat atten = light_attenuation (i);//angle to the Lightfloat 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 Colourlightcolor + = _lightcolor0.rgb * (diff * Atten); Product the final colorc.rgb = Lightcolor * C.rgb * 2;return simulatefog (I.viewspacepos, c);} ENDCG}} FallBack "Diffuse"}
written in the last
the Unity document reads:
Note that if the useFragment Programs, Fog settings of the shader would still be applied. On platforms where there is no fixed function Fog functionality, Unity would patch shaders at runtime-to-support the Reques Ted Fog mode.
that is, even if we are using our own fragment Shader, we will still be affected by Unity Render settings. Even the custom vertex & Fragment Shader in Unity should also be an upper-level function that does not know how many layers have been encapsulated by unity. If global fog is turned on, unity will use the Fog directive in the fixed rendering pipeline behind it to simulate fog effects. So, for a platform that doesn't support a fog-effect function for a fixed pipeline, it uses its own shader (like we did above) to simulate fog effects.
Reference:theOpenGL 4 sharding Language Cookbook"
"Unity Shaders" in unity fog effect simulation