1 Shader "Hidden/GlobalFog" {
2 Properties {
3 _MainTex ("Base (RGB)", 2D) = "black" {}
4 }
5
6 CGINCLUDE
7
8 #include "UnityCG.cginc"
9
10 uniform sampler2D _MainTex;
11 uniform sampler2D_float _CameraDepthTexture;
12
13 // x = fog height
14 // y = FdotC (CameraY-FogHeight)
15 // z = k (FdotC > 0.0)
16 // w = a/2
17 uniform float4 _HeightParams;
18
19 // x = start distance
20 uniform float4 _DistanceParams;
21
22 int4 _SceneFogMode; // x = fog mode, y = use radial flag
23 float4 _SceneFogParams;
24 #ifndef UNITY_APPLY_FOG
25 half4 unity_FogColor;
26 half4 unity_FogDensity;
27 #endif
28
29 uniform float4 _MainTex_TexelSize;
30
31 // for fast world space reconstruction
32 uniform float4x4 _FrustumCornersWS;
33 uniform float4 _CameraWS;
34
35 struct v2f {
36 float4 pos : SV_POSITION;
37 float2 uv : TEXCOORD0;
38 float2 uv_depth : TEXCOORD1;
39 float4 interpolatedRay : TEXCOORD2;
40 };
41
42 v2f vert (appdata_img v)
43 {
44 v2f o;
45 half index = v.vertex.z;
46 v.vertex.z = 0.1;
47 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
48 o.uv = v.texcoord.xy;
49 o.uv_depth = v.texcoord.xy;
50
51 #if UNITY_UV_STARTS_AT_TOP
52 if (_MainTex_TexelSize.y < 0)
53 o.uv.y = 1-o.uv.y;
54 #endif
55
56 o.interpolatedRay = _FrustumCornersWS[(int)index];
57 o.interpolatedRay.w = index;
58
59 return o;
60 }
61
62 // Applies one of standard fog formulas, given fog coordinate (i.e. distance)
63 half ComputeFogFactor (float coord)
64 {
65 float fogFac = 0.0;
66 if (_SceneFogMode.x == 1) // linear
67 {
68 // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
69 fogFac = coord * _SceneFogParams.z + _SceneFogParams.w;
70 }
71 if (_SceneFogMode.x == 2) // exp
72 {
73 // factor = exp(-density*z)
74 fogFac = _SceneFogParams.y * coord; fogFac = exp2(-fogFac);
75 }
76 if (_SceneFogMode.x == 3) // exp2
77 {
78 // factor = exp(-(density*z)^2)
79 fogFac = _SceneFogParams.x * coord; fogFac = exp2(-fogFac*fogFac);
80 }
81 return saturate(fogFac);
82 }
83
84 // Distance-based fog
85 float ComputeDistance (float3 camDir, float zdepth)
86 {
87 float dist;
88 if (_SceneFogMode.y == 1)
89 dist = length(camDir);
90 else
91 dist = zdepth * _ProjectionParams.z;
92 // Built-in fog starts at near plane, so match that by
93 // subtracting the near value. Not a perfect approximation
94 // if near plane is very large, but good enough.
95 dist -= _ProjectionParams.y;
96 return dist;
97 }
98
99 // Linear half-space fog, from https://www.terathon.com/lengyel/Lengyel-UnifiedFog.pdf
100 float ComputeHalfSpace (float3 wsDir)
101 {
102 float3 wpos = _CameraWS + wsDir;
103 float FH = _HeightParams.x;
104 float3 C = _CameraWS;
105 float3 V = wsDir;
106 float3 P = wpos;
107 float3 aV = _HeightParams.w * V;
108 float FdotC = _HeightParams.y;
109 float k = _HeightParams.z;
110 float FdotP = P.y-FH;
111 float FdotV = wsDir.y;
112 float c1 = k * (FdotP + FdotC);
113 float c2 = (1-2*k) * FdotP;
114 float g = min(c2, 0.0);
115 g = -length(aV) * (c1 - g * g / abs(FdotV+1.0e-5f));
116 return g;
117 }
118
119 half4 ComputeFog (v2f i, bool distance, bool height) : SV_Target
120 {
121 half4 sceneColor = tex2D(_MainTex, i.uv);
122
123 // Reconstruct world space position & direction
124 // towards this screen pixel.
125 float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth);
126 float dpth = Linear01Depth(rawDepth);
127 float4 wsDir = dpth * i.interpolatedRay;
128 float4 wsPos = _CameraWS + wsDir;
129
130 // Compute fog distance
131 float g = _DistanceParams.x;
132 if (distance)
133 g += ComputeDistance (wsDir, dpth);
134 if (height)
135 g += ComputeHalfSpace (wsDir);
136
137 // Compute fog amount
138 half fogFac = ComputeFogFactor (max(0.0,g));
139 // Do not fog skybox
140 if (rawDepth >= 0.999999)
141 fogFac = 1.0;
142 //return fogFac; // for debugging
143
144 // Lerp between fog color & original scene color
145 // by fog amount
146 return lerp (unity_FogColor, sceneColor, fogFac);
147 }
148
149 ENDCG
150
151 SubShader
152 {
153 ZTest Always Cull Off ZWrite Off Fog { Mode Off }
154
155 // 0: distance + height
156 Pass
157 {
158 CGPROGRAM
159 #pragma vertex vert
160 #pragma fragment frag
161 half4 frag (v2f i) : SV_Target { return ComputeFog (i, true, true); }
162 ENDCG
163 }
164 // 1: distance
165 Pass
166 {
167 CGPROGRAM
168 #pragma vertex vert
169 #pragma fragment frag
170 half4 frag (v2f i) : SV_Target { return ComputeFog (i, true, false); }
171 ENDCG
172 }
173 // 2: height
174 Pass
175 {
176 CGPROGRAM
177 #pragma vertex vert
178 #pragma fragment frag
179 half4 frag (v2f i) : SV_Target { return ComputeFog (i, false, true); }
180 ENDCG
181 }
182 }
183
184 Fallback off
185
186 }