暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RealtimeLights.hlsl 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #ifndef UNIVERSAL_REALTIME_LIGHTS_INCLUDED
  2. #define UNIVERSAL_REALTIME_LIGHTS_INCLUDED
  3. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
  4. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
  5. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
  6. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookie.hlsl"
  7. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Clustering.hlsl"
  8. // Abstraction over Light shading data.
  9. struct Light
  10. {
  11. half3 direction;
  12. half3 color;
  13. float distanceAttenuation; // full-float precision required on some platforms
  14. half shadowAttenuation;
  15. uint layerMask;
  16. };
  17. #if USE_FORWARD_PLUS && defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
  18. #define FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK if (_AdditionalLightsColor[lightIndex].a > 0.0h) continue;
  19. #else
  20. #define FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
  21. #endif
  22. #if USE_FORWARD_PLUS
  23. #define LIGHT_LOOP_BEGIN(lightCount) { \
  24. uint lightIndex; \
  25. ClusterIterator _urp_internal_clusterIterator = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 0); \
  26. [loop] while (ClusterNext(_urp_internal_clusterIterator, lightIndex)) { \
  27. lightIndex += URP_FP_DIRECTIONAL_LIGHTS_COUNT; \
  28. FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
  29. #define LIGHT_LOOP_END } }
  30. #else
  31. #define LIGHT_LOOP_BEGIN(lightCount) \
  32. for (uint lightIndex = 0u; lightIndex < lightCount; ++lightIndex) {
  33. #define LIGHT_LOOP_END }
  34. #endif
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // Attenuation Functions /
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // Matches Unity Vanilla HINT_NICE_QUALITY attenuation
  39. // Attenuation smoothly decreases to light range.
  40. float DistanceAttenuation(float distanceSqr, half2 distanceAttenuation)
  41. {
  42. // We use a shared distance attenuation for additional directional and puctual lights
  43. // for directional lights attenuation will be 1
  44. float lightAtten = rcp(distanceSqr);
  45. float2 distanceAttenuationFloat = float2(distanceAttenuation);
  46. // Use the smoothing factor also used in the Unity lightmapper.
  47. half factor = half(distanceSqr * distanceAttenuationFloat.x);
  48. half smoothFactor = saturate(half(1.0) - factor * factor);
  49. smoothFactor = smoothFactor * smoothFactor;
  50. return lightAtten * smoothFactor;
  51. }
  52. half AngleAttenuation(half3 spotDirection, half3 lightDirection, half2 spotAttenuation)
  53. {
  54. // Spot Attenuation with a linear falloff can be defined as
  55. // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
  56. // This can be rewritten as
  57. // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
  58. // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
  59. // SdotL * spotAttenuation.x + spotAttenuation.y
  60. // If we precompute the terms in a MAD instruction
  61. half SdotL = dot(spotDirection, lightDirection);
  62. half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
  63. return atten * atten;
  64. }
  65. ///////////////////////////////////////////////////////////////////////////////
  66. // Light Abstraction //
  67. ///////////////////////////////////////////////////////////////////////////////
  68. Light GetMainLight()
  69. {
  70. Light light;
  71. light.direction = half3(_MainLightPosition.xyz);
  72. #if USE_FORWARD_PLUS
  73. #if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
  74. light.distanceAttenuation = _MainLightColor.a;
  75. #else
  76. light.distanceAttenuation = 1.0;
  77. #endif
  78. #else
  79. light.distanceAttenuation = unity_LightData.z; // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.
  80. #endif
  81. light.shadowAttenuation = 1.0;
  82. light.color = _MainLightColor.rgb;
  83. light.layerMask = _MainLightLayerMask;
  84. return light;
  85. }
  86. Light GetMainLight(float4 shadowCoord)
  87. {
  88. Light light = GetMainLight();
  89. light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
  90. return light;
  91. }
  92. Light GetMainLight(float4 shadowCoord, float3 positionWS, half4 shadowMask)
  93. {
  94. Light light = GetMainLight();
  95. light.shadowAttenuation = MainLightShadow(shadowCoord, positionWS, shadowMask, _MainLightOcclusionProbes);
  96. #if defined(_LIGHT_COOKIES)
  97. real3 cookieColor = SampleMainLightCookie(positionWS);
  98. light.color *= cookieColor;
  99. #endif
  100. return light;
  101. }
  102. Light GetMainLight(InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
  103. {
  104. Light light = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
  105. #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
  106. if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
  107. {
  108. light.color *= aoFactor.directAmbientOcclusion;
  109. }
  110. #endif
  111. return light;
  112. }
  113. // Fills a light struct given a perObjectLightIndex
  114. Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
  115. {
  116. // Abstraction over Light input constants
  117. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  118. float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
  119. half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
  120. half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
  121. half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
  122. uint lightLayerMask = _AdditionalLightsBuffer[perObjectLightIndex].layerMask;
  123. #else
  124. float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
  125. half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
  126. half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
  127. half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
  128. uint lightLayerMask = asuint(_AdditionalLightsLayerMasks[perObjectLightIndex]);
  129. #endif
  130. // Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
  131. // This way the following code will work for both directional and punctual lights.
  132. float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
  133. float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
  134. half3 lightDirection = half3(lightVector * rsqrt(distanceSqr));
  135. // full-float precision required on some platforms
  136. float attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
  137. Light light;
  138. light.direction = lightDirection;
  139. light.distanceAttenuation = attenuation;
  140. light.shadowAttenuation = 1.0; // This value can later be overridden in GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
  141. light.color = color;
  142. light.layerMask = lightLayerMask;
  143. return light;
  144. }
  145. uint GetPerObjectLightIndexOffset()
  146. {
  147. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  148. return uint(unity_LightData.x);
  149. #else
  150. return 0;
  151. #endif
  152. }
  153. // Returns a per-object index given a loop index.
  154. // This abstract the underlying data implementation for storing lights/light indices
  155. int GetPerObjectLightIndex(uint index)
  156. {
  157. /////////////////////////////////////////////////////////////////////////////////////////////
  158. // Structured Buffer Path /
  159. // /
  160. // Lights and light indices are stored in StructuredBuffer. We can just index them. /
  161. // Currently all non-mobile platforms take this path :( /
  162. // There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) /
  163. /////////////////////////////////////////////////////////////////////////////////////////////
  164. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  165. uint offset = uint(unity_LightData.x);
  166. return _AdditionalLightsIndices[offset + index];
  167. /////////////////////////////////////////////////////////////////////////////////////////////
  168. // UBO path /
  169. // /
  170. // We store 8 light indices in half4 unity_LightIndices[2]; /
  171. // Due to memory alignment unity doesn't support int[] or float[] /
  172. // Even trying to reinterpret cast the unity_LightIndices to float[] won't work /
  173. // it will cast to float4[] and create extra register pressure. :( /
  174. /////////////////////////////////////////////////////////////////////////////////////////////
  175. #else
  176. // since index is uint shader compiler will implement
  177. // div & mod as bitfield ops (shift and mask).
  178. // TODO: Can we index a float4? Currently compiler is
  179. // replacing unity_LightIndicesX[i] with a dp4 with identity matrix.
  180. // u_xlat16_40 = dot(unity_LightIndices[int(u_xlatu13)], ImmCB_0_0_0[u_xlati1]);
  181. // This increases both arithmetic and register pressure.
  182. //
  183. // NOTE: min16float4 bug workaround.
  184. // Take the "vec4" part into float4 tmp variable in order to force float4 math.
  185. // It appears indexing half4 as min16float4 on DX11 can fail. (dp4 {min16f})
  186. float4 tmp = unity_LightIndices[index / 4];
  187. return int(tmp[index % 4]);
  188. #endif
  189. }
  190. // Fills a light struct given a loop i index. This will convert the i
  191. // index to a perObjectLightIndex
  192. Light GetAdditionalLight(uint i, float3 positionWS)
  193. {
  194. #if USE_FORWARD_PLUS
  195. int lightIndex = i;
  196. #else
  197. int lightIndex = GetPerObjectLightIndex(i);
  198. #endif
  199. return GetAdditionalPerObjectLight(lightIndex, positionWS);
  200. }
  201. Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
  202. {
  203. #if USE_FORWARD_PLUS
  204. int lightIndex = i;
  205. #else
  206. int lightIndex = GetPerObjectLightIndex(i);
  207. #endif
  208. Light light = GetAdditionalPerObjectLight(lightIndex, positionWS);
  209. #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
  210. half4 occlusionProbeChannels = _AdditionalLightsBuffer[lightIndex].occlusionProbeChannels;
  211. #else
  212. half4 occlusionProbeChannels = _AdditionalLightsOcclusionProbes[lightIndex];
  213. #endif
  214. light.shadowAttenuation = AdditionalLightShadow(lightIndex, positionWS, light.direction, shadowMask, occlusionProbeChannels);
  215. #if defined(_LIGHT_COOKIES)
  216. real3 cookieColor = SampleAdditionalLightCookie(lightIndex, positionWS);
  217. light.color *= cookieColor;
  218. #endif
  219. return light;
  220. }
  221. Light GetAdditionalLight(uint i, InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
  222. {
  223. Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask);
  224. #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
  225. if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
  226. {
  227. light.color *= aoFactor.directAmbientOcclusion;
  228. }
  229. #endif
  230. return light;
  231. }
  232. int GetAdditionalLightsCount()
  233. {
  234. #if USE_FORWARD_PLUS
  235. // Counting the number of lights in clustered requires traversing the bit list, and is not needed up front.
  236. return 0;
  237. #else
  238. // TODO: we need to expose in SRP api an ability for the pipeline cap the amount of lights
  239. // in the culling. This way we could do the loop branch with an uniform
  240. // This would be helpful to support baking exceeding lights in SH as well
  241. return int(min(_AdditionalLightsCount.x, unity_LightData.y));
  242. #endif
  243. }
  244. half4 CalculateShadowMask(InputData inputData)
  245. {
  246. // To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
  247. #if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
  248. half4 shadowMask = inputData.shadowMask; // Shadowmask was sampled from lightmap
  249. #elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
  250. half4 shadowMask = inputData.shadowMask; // Shadowmask (probe occlusion) was sampled from APV
  251. #elif !defined (LIGHTMAP_ON)
  252. half4 shadowMask = unity_ProbesOcclusion; // Sample shadowmask (probe occlusion) from legacy probes
  253. #else
  254. half4 shadowMask = half4(1, 1, 1, 1); // Fallback shadowmask, fully unoccluded
  255. #endif
  256. return shadowMask;
  257. }
  258. #endif