GlobalFog.shader 4.3 KB

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