Lux URP FX BoxVolume.shader 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. Shader "Lux URP/FX/Box Volume"
  2. {
  3. Properties
  4. {
  5. [HeaderHelpLuxURP_URL(t98mzd66fi0m)]
  6. [Header(Surface Options)]
  7. [Space(8)]
  8. [Enum(UnityEngine.Rendering.CompareFunction)]
  9. _ZTest ("ZTest", Int) = 8
  10. [Enum(UnityEngine.Rendering.CullMode)]
  11. _Cull ("Culling", Float) = 1
  12. [Toggle(ORTHO_SUPPORT)]
  13. _OrthoSpport ("Enable Orthographic Support", Float) = 0
  14. [Header(Surface Inputs)]
  15. [Space(8)]
  16. _Color ("Color", Color) = (1,1,1,1)
  17. [Toggle(_ENABLEGRADIENT)]
  18. _EnableGradient ("Enable Gradient", Float) = 0
  19. [NoScaleOffset]
  20. _MainTex (" Vertical Gradient", 2D) = "white" {}
  21. [Header(Thickness Remap)]
  22. [Space(8)]
  23. _Lower (" Lower", Range(0,1)) = 0
  24. _Upper (" Upper", Range(0,4)) = 1
  25. //[Space(5)]
  26. //_SoftEdge (" Soft Edge Factor", Float) = 2.0
  27. [Space(5)]
  28. [Toggle(_APPLYFOG)]
  29. _ApplyFog ("Enable Fog", Float) = 0.0
  30. [Toggle(_HQFOG)]
  31. _HQFog (" HQ Fog", Float) = 0.0
  32. }
  33. SubShader
  34. {
  35. Tags
  36. {
  37. "RenderPipeline" = "UniversalPipeline"
  38. "RenderType"="Transparent"
  39. "Queue"="Transparent+50"
  40. }
  41. Pass
  42. {
  43. Name "StandardUnlit"
  44. Tags{"LightMode" = "UniversalForward"}
  45. Blend SrcAlpha OneMinusSrcAlpha
  46. // As we want to be able to enter the volume we have to draw the back faces
  47. Cull [_Cull]
  48. // We fully rely on the depth texture sample!
  49. ZTest [_ZTest]
  50. ZWrite Off
  51. HLSLPROGRAM
  52. // Required to compile gles 2.0 with standard srp library
  53. #pragma prefer_hlslcc gles
  54. #pragma exclude_renderers d3d11_9x
  55. #pragma target 2.0
  56. #pragma shader_feature_local _ENABLEGRADIENT
  57. #pragma shader_feature_local _APPLYFOG
  58. #pragma shader_feature_local ORTHO_SUPPORT
  59. // -------------------------------------
  60. // Lightweight Pipeline keywords
  61. // -------------------------------------
  62. // Unity defined keywords
  63. #if defined(_APPLYFOG)
  64. #pragma multi_compile_fog
  65. #pragma shader_feature_local _HQFOG
  66. #endif
  67. //--------------------------------------
  68. // GPU Instancing
  69. #pragma multi_compile_instancing
  70. #pragma vertex vert
  71. #pragma fragment frag
  72. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  73. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
  74. #include "Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl"
  75. CBUFFER_START(UnityPerMaterial)
  76. half4 _Color;
  77. half _Lower;
  78. half _Upper;
  79. //half _SoftEdge;
  80. CBUFFER_END
  81. #if defined(_ENABLEGRADIENT)
  82. TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
  83. #endif
  84. #if defined(SHADER_API_GLES)
  85. TEXTURE2D(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture);
  86. #else
  87. TEXTURE2D_X_FLOAT(_CameraDepthTexture);
  88. #endif
  89. float4 _CameraDepthTexture_TexelSize;
  90. struct VertexInput
  91. {
  92. float4 vertex : POSITION;
  93. UNITY_VERTEX_INPUT_INSTANCE_ID
  94. };
  95. struct VertexOutput
  96. {
  97. float4 positionCS : SV_POSITION;
  98. float3 positionWS : TEXCOORD1;
  99. float2 projectedPosition : TEXCOORD2;
  100. float3 cameraPositionOS : TEXCOORD3;
  101. float scale : TEXCOORD4;
  102. #if defined(_APPLYFOG)
  103. half fogCoord : TEXCOORD5;
  104. #endif
  105. float4 viewRayOS : TEXCOORD6;
  106. UNITY_VERTEX_INPUT_INSTANCE_ID
  107. UNITY_VERTEX_OUTPUT_STEREO
  108. };
  109. float IntersectRayBox(float3 rayOrigin, float3 rayDirection,
  110. out float tEntr, out float tExit)
  111. {
  112. // Could be precomputed. Clamp to avoid INF. clamp() is a single ALU on GCN.
  113. // rcp(FLT_EPS) = 16,777,216, which is large enough for our purposes,
  114. // yet doesn't cause a lot of numerical issues associated with FLT_MAX.
  115. float3 rayDirInv = clamp(rcp(rayDirection), -rcp(FLT_EPS), rcp(FLT_EPS));
  116. // Perform ray-slab intersection (component-wise).
  117. float3 boxMin = float3(-0.5, -0.5, -0.5);
  118. float3 boxMax = float3( 0.5, 0.5, 0.5);
  119. float3 t0 = boxMin * rayDirInv - (rayOrigin * rayDirInv);
  120. float3 t1 = boxMax * rayDirInv - (rayOrigin * rayDirInv);
  121. // Find the closest/farthest distance (component-wise).
  122. float3 tSlabEntr = min(t0, t1);
  123. float3 tSlabExit = max(t0, t1);
  124. // Find the farthest entry and the nearest exit.
  125. tEntr = Max3(tSlabEntr.x, tSlabEntr.y, tSlabEntr.z);
  126. tExit = Min3(tSlabExit.x, tSlabExit.y, tSlabExit.z);
  127. // When the camera is inside the volume we may get negative values so the box from behind the camera gets "mirrored" into the view.
  128. // Using max(0, ) suppresses these artifacts.
  129. tEntr = max(0.0f, tEntr);
  130. return tExit - tEntr;
  131. }
  132. VertexOutput vert (VertexInput v)
  133. {
  134. VertexOutput o = (VertexOutput)0;
  135. UNITY_SETUP_INSTANCE_ID(v);
  136. UNITY_TRANSFER_INSTANCE_ID(v, o);
  137. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
  138. //
  139. VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
  140. o.positionCS = vertexInput.positionCS;
  141. o.projectedPosition = vertexInput.positionNDC.xy;
  142. o.positionWS = vertexInput.positionWS;
  143. o.cameraPositionOS = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)).xyz;
  144. float4x4 ObjectToWorldMatrix = GetObjectToWorldMatrix();
  145. float3 worldScale = float3(
  146. length(ObjectToWorldMatrix._m00_m10_m20), // scale x axis
  147. length(ObjectToWorldMatrix._m01_m11_m21), // scale y axis
  148. length(ObjectToWorldMatrix._m02_m12_m22) // scale z axis
  149. );
  150. o.scale = 1.0f / max(worldScale.x, max(worldScale.y, worldScale.z));
  151. #if defined(_APPLYFOG)
  152. o.fogCoord = ComputeFogFactor(o.positionCS.z);
  153. #endif
  154. float4 positionVS = mul(UNITY_MATRIX_V, mul(UNITY_MATRIX_M, v.vertex)); //mul(UNITY_MATRIX_MV, v.vertex);
  155. float3 viewRayVS = positionVS.xyz;
  156. // NOTE: Fix direction of the viewRay
  157. float4x4 ViewToObjectMatrix = mul(GetWorldToObjectMatrix(), UNITY_MATRIX_I_V);
  158. o.viewRayOS.xyz = mul((float3x3)ViewToObjectMatrix, -viewRayVS).xyz;
  159. // positionVS.z here acts as view space to object space ratio (negative)
  160. o.viewRayOS.w = positionVS.z;
  161. return o;
  162. }
  163. real LuxComputeFogFactor(float z)
  164. {
  165. float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z);
  166. #if defined(FOG_LINEAR)
  167. // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
  168. float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
  169. return real(fogFactor);
  170. #elif defined(FOG_EXP) || defined(FOG_EXP2)
  171. // factor = exp(-(density*z)^2)
  172. // -density * z computed at vertex
  173. return real(unity_FogParams.x * clipZ_01);
  174. #else
  175. return 0.0h;
  176. #endif
  177. }
  178. // ------------------------------------------------------------------
  179. // Helper functions to handle orthographic / perspective projection
  180. inline float GetOrthoDepthFromZBuffer (float rawDepth) {
  181. #if defined(UNITY_REVERSED_Z)
  182. // Needed to handle openGL
  183. #if UNITY_REVERSED_Z == 1
  184. rawDepth = 1.0f - rawDepth;
  185. #endif
  186. #endif
  187. return lerp(_ProjectionParams.y, _ProjectionParams.z, rawDepth);
  188. }
  189. inline float GetProperEyeDepth (float rawDepth) {
  190. #if defined(ORTHO_SUPPORT)
  191. float perspectiveSceneDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
  192. float orthoSceneDepth = GetOrthoDepthFromZBuffer(rawDepth);
  193. return lerp(perspectiveSceneDepth, orthoSceneDepth, unity_OrthoParams.w);
  194. #else
  195. return LinearEyeDepth(rawDepth, _ZBufferParams);
  196. #endif
  197. }
  198. half4 frag (VertexOutput input ) : SV_Target
  199. {
  200. UNITY_SETUP_INSTANCE_ID(input);
  201. UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
  202. half4 color = half4(1,1,1,0);
  203. float3 rayDir = input.viewRayOS.xyz / input.viewRayOS.w;
  204. float3 rayStart = input.cameraPositionOS;
  205. float2 screenUV = input.projectedPosition.xy / input.positionCS.w;
  206. // Fix screenUV for Single Pass Stereo Rendering
  207. #if defined(UNITY_SINGLE_PASS_STEREO)
  208. screenUV.x = screenUV.x * 0.5f + (float)unity_StereoEyeIndex * 0.5f;
  209. #endif
  210. #if defined(SHADER_API_GLES)
  211. float sceneZ = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, screenUV, 0);
  212. #else
  213. float sceneZ = LOAD_TEXTURE2D_X(_CameraDepthTexture, _CameraDepthTexture_TexelSize.zw * screenUV).x;
  214. #endif
  215. sceneZ = GetProperEyeDepth(sceneZ);
  216. float near;
  217. float far;
  218. float thickness = IntersectRayBox(rayStart, rayDir, near, far);
  219. // Entry point in object space
  220. float3 entryOS = rayStart + rayDir * near;
  221. float distanceToEntryOS = length(entryOS - input.cameraPositionOS);
  222. float sceneDistanceOS = length(sceneZ * rayDir);
  223. float sceneToEntry = sceneDistanceOS - distanceToEntryOS;
  224. // Nothing to do if the scene is in front of the entry point
  225. clip(sceneToEntry);
  226. // Exit point in object space
  227. float3 exitOS = rayStart + rayDir * far;
  228. float maxTravel = distance(exitOS, entryOS);
  229. float denom = min(sceneToEntry, maxTravel);
  230. float percentage = maxTravel / denom;
  231. percentage = rcp(percentage);
  232. float alpha = thickness * input.scale * percentage;
  233. // Smooth falloff
  234. alpha = smoothstep(_Lower, _Upper, alpha);
  235. // Scene blending - as otherwise we may get 1px wide artifacts at the borders.
  236. //alpha *= saturate(sceneToEntry / _SoftEdge );
  237. // saturate eliminates artifacts at grazing angles
  238. color.a = saturate(alpha);
  239. #if defined(_ENABLEGRADIENT)
  240. color.rgb = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(exitOS.y + 0.5, 0)).rgb;
  241. #endif
  242. color *= _Color;
  243. // Here was a nasty bug!
  244. #if defined(_APPLYFOG)
  245. #if defined(_HQFOG)
  246. float3 exitFog = mul(GetObjectToWorldMatrix(), float4(rayStart + rayDir * far * sqrt(percentage), 1)).xyz;
  247. float4 FogClipSpace = TransformWorldToHClip(exitFog);
  248. float fogFactor = LuxComputeFogFactor( FogClipSpace.z);
  249. color.rgb = MixFog(color.rgb, fogFactor);
  250. #else
  251. color.rgb = MixFog(color.rgb, input.fogCoord);
  252. #endif
  253. #endif
  254. return color;
  255. }
  256. ENDHLSL
  257. }
  258. }
  259. FallBack "Hidden/InternalErrorShader"
  260. }