No Description
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.

RendererLighting.cs 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. using System.Collections.Generic;
  2. using UnityEngine.Experimental.Rendering;
  3. using Unity.Collections;
  4. using System;
  5. using Unity.Mathematics;
  6. namespace UnityEngine.Rendering.Universal
  7. {
  8. internal static class RendererLighting
  9. {
  10. private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler("Draw Normals");
  11. private static readonly ShaderTagId k_NormalsRenderingPassName = new ShaderTagId("NormalsRendering");
  12. public static readonly Color k_NormalClearColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
  13. private static readonly string k_UsePointLightCookiesKeyword = "USE_POINT_LIGHT_COOKIES";
  14. private static readonly string k_LightQualityFastKeyword = "LIGHT_QUALITY_FAST";
  15. private static readonly string k_UseNormalMap = "USE_NORMAL_MAP";
  16. private static readonly string k_UseAdditiveBlendingKeyword = "USE_ADDITIVE_BLENDING";
  17. private static readonly string k_UseVolumetric = "USE_VOLUMETRIC";
  18. private static readonly string[] k_UseBlendStyleKeywords =
  19. {
  20. "USE_SHAPE_LIGHT_TYPE_0", "USE_SHAPE_LIGHT_TYPE_1", "USE_SHAPE_LIGHT_TYPE_2", "USE_SHAPE_LIGHT_TYPE_3"
  21. };
  22. private static readonly int[] k_BlendFactorsPropIDs =
  23. {
  24. Shader.PropertyToID("_ShapeLightBlendFactors0"),
  25. Shader.PropertyToID("_ShapeLightBlendFactors1"),
  26. Shader.PropertyToID("_ShapeLightBlendFactors2"),
  27. Shader.PropertyToID("_ShapeLightBlendFactors3")
  28. };
  29. private static readonly int[] k_MaskFilterPropIDs =
  30. {
  31. Shader.PropertyToID("_ShapeLightMaskFilter0"),
  32. Shader.PropertyToID("_ShapeLightMaskFilter1"),
  33. Shader.PropertyToID("_ShapeLightMaskFilter2"),
  34. Shader.PropertyToID("_ShapeLightMaskFilter3")
  35. };
  36. private static readonly int[] k_InvertedFilterPropIDs =
  37. {
  38. Shader.PropertyToID("_ShapeLightInvertedFilter0"),
  39. Shader.PropertyToID("_ShapeLightInvertedFilter1"),
  40. Shader.PropertyToID("_ShapeLightInvertedFilter2"),
  41. Shader.PropertyToID("_ShapeLightInvertedFilter3")
  42. };
  43. public static readonly string[] k_ShapeLightTextureIDs =
  44. {
  45. "_ShapeLightTexture0",
  46. "_ShapeLightTexture1",
  47. "_ShapeLightTexture2",
  48. "_ShapeLightTexture3"
  49. };
  50. private static GraphicsFormat s_RenderTextureFormatToUse = GraphicsFormat.R8G8B8A8_UNorm;
  51. private static bool s_HasSetupRenderTextureFormatToUse;
  52. private static readonly int k_SrcBlendID = Shader.PropertyToID("_SrcBlend");
  53. private static readonly int k_DstBlendID = Shader.PropertyToID("_DstBlend");
  54. private static readonly int k_CookieTexID = Shader.PropertyToID("_CookieTex");
  55. private static readonly int k_PointLightCookieTexID = Shader.PropertyToID("_PointLightCookieTex");
  56. private static readonly int k_L2DInvMatrix = Shader.PropertyToID("L2DInvMatrix");
  57. private static readonly int k_L2DColor = Shader.PropertyToID("L2DColor");
  58. private static readonly int k_L2DPosition = Shader.PropertyToID("L2DPosition");
  59. private static readonly int k_L2DFalloffIntensity = Shader.PropertyToID("L2DFalloffIntensity");
  60. private static readonly int k_L2DFalloffDistance = Shader.PropertyToID("L2DFalloffDistance");
  61. private static readonly int k_L2DOuterAngle = Shader.PropertyToID("L2DOuterAngle");
  62. private static readonly int k_L2DInnerAngle = Shader.PropertyToID("L2DInnerAngle");
  63. private static readonly int k_L2DInnerRadiusMult = Shader.PropertyToID("L2DInnerRadiusMult");
  64. private static readonly int k_L2DVolumeOpacity = Shader.PropertyToID("L2DVolumeOpacity");
  65. private static readonly int k_L2DShadowIntensity = Shader.PropertyToID("L2DShadowIntensity");
  66. private static readonly int k_L2DLightType = Shader.PropertyToID("L2DLightType");
  67. // Light Batcher.
  68. internal static LightBatch lightBatch = new LightBatch();
  69. internal static GraphicsFormat GetRenderTextureFormat()
  70. {
  71. if (!s_HasSetupRenderTextureFormatToUse)
  72. {
  73. // UUM-41070: We require `Linear | Render` but with the deprecated FormatUsage this was checking `Blend`
  74. // For now, we keep checking for `Blend` until the performance hit of doing the correct checks is evaluated
  75. if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, GraphicsFormatUsage.Blend))
  76. s_RenderTextureFormatToUse = GraphicsFormat.B10G11R11_UFloatPack32;
  77. else if (SystemInfo.IsFormatSupported(GraphicsFormat.R16G16B16A16_SFloat, GraphicsFormatUsage.Blend))
  78. s_RenderTextureFormatToUse = GraphicsFormat.R16G16B16A16_SFloat;
  79. s_HasSetupRenderTextureFormatToUse = true;
  80. }
  81. return s_RenderTextureFormatToUse;
  82. }
  83. public static void CreateNormalMapRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, float renderScale)
  84. {
  85. var descriptor = new RenderTextureDescriptor(
  86. (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderScale),
  87. (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderScale));
  88. descriptor.graphicsFormat = GetRenderTextureFormat();
  89. descriptor.useMipMap = false;
  90. descriptor.autoGenerateMips = false;
  91. descriptor.depthBufferBits = 0;
  92. descriptor.msaaSamples = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
  93. descriptor.dimension = TextureDimension.Tex2D;
  94. RenderingUtils.ReAllocateHandleIfNeeded(ref pass.rendererData.normalsRenderTarget, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_NormalMap");
  95. cmd.SetGlobalTexture(pass.rendererData.normalsRenderTarget.name, pass.rendererData.normalsRenderTarget.nameID);
  96. }
  97. public static RenderTextureDescriptor GetBlendStyleRenderTextureDesc(this IRenderPass2D pass, RenderingData renderingData)
  98. {
  99. var renderTextureScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
  100. var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
  101. var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
  102. var descriptor = new RenderTextureDescriptor(width, height);
  103. descriptor.graphicsFormat = GetRenderTextureFormat();
  104. descriptor.useMipMap = false;
  105. descriptor.autoGenerateMips = false;
  106. descriptor.depthBufferBits = 0;
  107. descriptor.msaaSamples = 1;
  108. descriptor.dimension = TextureDimension.Tex2D;
  109. return descriptor;
  110. }
  111. public static void CreateCameraSortingLayerRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, Downsampling downsamplingMethod)
  112. {
  113. var renderTextureScale = 1.0f;
  114. if (downsamplingMethod == Downsampling._2xBilinear)
  115. renderTextureScale = 0.5f;
  116. else if (downsamplingMethod == Downsampling._4xBox || downsamplingMethod == Downsampling._4xBilinear)
  117. renderTextureScale = 0.25f;
  118. var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
  119. var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
  120. var descriptor = new RenderTextureDescriptor(width, height);
  121. descriptor.graphicsFormat = renderingData.cameraData.cameraTargetDescriptor.graphicsFormat;
  122. descriptor.useMipMap = false;
  123. descriptor.autoGenerateMips = false;
  124. descriptor.depthBufferBits = 0;
  125. descriptor.msaaSamples = 1;
  126. descriptor.graphicsFormat = GraphicsFormat.B10G11R11_UFloatPack32;
  127. descriptor.dimension = TextureDimension.Tex2D;
  128. RenderingUtils.ReAllocateHandleIfNeeded(ref pass.rendererData.cameraSortingLayerRenderTarget, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: "_CameraSortingLayerTexture");
  129. cmd.SetGlobalTexture(pass.rendererData.cameraSortingLayerRenderTarget.name, pass.rendererData.cameraSortingLayerRenderTarget.nameID);
  130. }
  131. internal static void EnableBlendStyle(IRasterCommandBuffer cmd, int blendStyleIndex, bool enabled)
  132. {
  133. var keyword = k_UseBlendStyleKeywords[blendStyleIndex];
  134. if (enabled)
  135. cmd.EnableShaderKeyword(keyword);
  136. else
  137. cmd.DisableShaderKeyword(keyword);
  138. }
  139. internal static void DisableAllKeywords(RasterCommandBuffer cmd)
  140. {
  141. foreach (var keyword in k_UseBlendStyleKeywords)
  142. {
  143. cmd.DisableShaderKeyword(keyword);
  144. }
  145. }
  146. internal static void GetTransparencySortingMode(Renderer2DData rendererData, Camera camera, ref SortingSettings sortingSettings)
  147. {
  148. var mode = rendererData.transparencySortMode;
  149. if (mode == TransparencySortMode.Default)
  150. {
  151. mode = camera.orthographic ? TransparencySortMode.Orthographic : TransparencySortMode.Perspective;
  152. }
  153. switch (mode)
  154. {
  155. case TransparencySortMode.Perspective:
  156. sortingSettings.distanceMetric = DistanceMetric.Perspective;
  157. break;
  158. case TransparencySortMode.Orthographic:
  159. sortingSettings.distanceMetric = DistanceMetric.Orthographic;
  160. break;
  161. default:
  162. sortingSettings.distanceMetric = DistanceMetric.CustomAxis;
  163. sortingSettings.customAxis = rendererData.transparencySortAxis;
  164. break;
  165. }
  166. }
  167. private static bool CanRenderLight(IRenderPass2D pass, Light2D light, int blendStyleIndex, int layerToRender, bool isVolume, ref Mesh lightMesh, ref Material lightMaterial)
  168. {
  169. if (light != null && light.lightType != Light2D.LightType.Global && light.blendStyleIndex == blendStyleIndex && light.IsLitLayer(layerToRender))
  170. {
  171. lightMesh = light.lightMesh;
  172. if (lightMesh == null)
  173. return false;
  174. lightMaterial = pass.rendererData.GetLightMaterial(light, isVolume);
  175. if (lightMaterial == null)
  176. return false;
  177. return true;
  178. }
  179. return false;
  180. }
  181. internal static bool CanCastShadows(Light2D light, int layerToRender)
  182. {
  183. return light.shadowsEnabled && light.shadowIntensity > 0 && light.IsLitLayer(layerToRender);
  184. }
  185. private static bool CanCastVolumetricShadows(Light2D light, int endLayerValue)
  186. {
  187. var topMostLayerValue = light.GetTopMostLitLayer();
  188. return light.volumetricShadowsEnabled && light.shadowVolumeIntensity > 0 && topMostLayerValue == endLayerValue;
  189. }
  190. internal static void RenderLight(IRenderPass2D pass, CommandBuffer cmd, Light2D light, bool isVolume, int blendStyleIndex, int layerToRender, bool hasShadows, bool batchingSupported, ref int shadowLightCount)
  191. {
  192. Mesh lightMesh = null;
  193. Material lightMaterial = null;
  194. if (!CanRenderLight(pass, light, blendStyleIndex, layerToRender, isVolume, ref lightMesh, ref lightMaterial))
  195. return;
  196. // For Batching.
  197. bool canBatch = lightBatch.CanBatch(light, lightMaterial, light.batchSlotIndex, out int lightHash);
  198. bool hasCookies = SetCookieShaderGlobals(cmd, light);
  199. // Flush on Break.
  200. bool breakBatch = hasShadows || hasCookies || !canBatch;
  201. if (breakBatch && batchingSupported)
  202. lightBatch.Flush(CommandBufferHelpers.GetRasterCommandBuffer(cmd));
  203. // Set the shadow texture to read from
  204. if (hasShadows)
  205. ShadowRendering.SetGlobalShadowTexture(cmd, light, shadowLightCount++);
  206. var slotIndex = lightBatch.SlotIndex(light.batchSlotIndex);
  207. SetPerLightShaderGlobals(CommandBufferHelpers.GetRasterCommandBuffer(cmd), light, slotIndex, isVolume, hasShadows, batchingSupported);
  208. if (light.lightType == Light2D.LightType.Point)
  209. SetPerPointLightShaderGlobals(CommandBufferHelpers.GetRasterCommandBuffer(cmd), light, slotIndex, batchingSupported);
  210. // Check if StructuredBuffer is supported, if not fallback.
  211. if (batchingSupported)
  212. {
  213. lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, light.batchSlotIndex);
  214. }
  215. else
  216. {
  217. cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial);
  218. }
  219. }
  220. private static void RenderLightSet(IRenderPass2D pass, RenderingData renderingData, int blendStyleIndex, CommandBuffer cmd, ref LayerBatch layer, RenderTargetIdentifier renderTexture, List<Light2D> lights)
  221. {
  222. var maxShadowLightCount = ShadowRendering.maxTextureCount;
  223. var requiresRTInit = true;
  224. // This case should never happen, but if it does it may cause an infinite loop later.
  225. if (maxShadowLightCount < 1)
  226. {
  227. Debug.LogError("maxShadowTextureCount cannot be less than 1");
  228. return;
  229. }
  230. NativeArray<bool> doesLightAtIndexHaveShadows = new NativeArray<bool>(lights.Count, Allocator.Temp);
  231. // Break up light rendering into batches for the purpose of shadow casting
  232. var lightIndex = 0;
  233. while (lightIndex < lights.Count)
  234. {
  235. var remainingLights = (uint)lights.Count - lightIndex;
  236. var batchedLights = 0;
  237. // Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
  238. int shadowLightCount = 0;
  239. while (batchedLights < remainingLights && shadowLightCount < maxShadowLightCount)
  240. {
  241. int curLightIndex = lightIndex + batchedLights;
  242. var light = lights[curLightIndex];
  243. if (CanCastShadows(light, layer.startLayerID))
  244. {
  245. doesLightAtIndexHaveShadows[curLightIndex] = false;
  246. if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, ref layer, light, shadowLightCount, light.shadowIntensity))
  247. {
  248. doesLightAtIndexHaveShadows[curLightIndex] = true;
  249. shadowLightCount++;
  250. }
  251. }
  252. batchedLights++;
  253. }
  254. // Set the current RT to the light RT
  255. if (shadowLightCount > 0 || requiresRTInit)
  256. {
  257. cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
  258. requiresRTInit = false;
  259. }
  260. // Render all the lights.
  261. shadowLightCount = 0;
  262. for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
  263. {
  264. var arrayIndex = (int)(lightIndex + lightIndexOffset);
  265. RenderLight(pass, cmd, lights[arrayIndex], false, blendStyleIndex, layer.startLayerID, doesLightAtIndexHaveShadows[arrayIndex], LightBatch.isBatchingSupported, ref shadowLightCount);
  266. }
  267. lightBatch.Flush(CommandBufferHelpers.GetRasterCommandBuffer(cmd));
  268. // Release all of the temporary shadow textures
  269. for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
  270. ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
  271. lightIndex += batchedLights;
  272. }
  273. doesLightAtIndexHaveShadows.Dispose();
  274. }
  275. public static void RenderLightVolumes(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, ref LayerBatch layer,
  276. RenderTargetIdentifier renderTexture, RenderTargetIdentifier depthTexture, RenderBufferStoreAction intermediateStoreAction,
  277. RenderBufferStoreAction finalStoreAction, bool requiresRTInit, List<Light2D> lights)
  278. {
  279. var maxShadowLightCount = ShadowRendering.maxTextureCount; // Now encodes shadows into RG,BA as well as seperate textures
  280. NativeArray<bool> doesLightAtIndexHaveShadows = new NativeArray<bool>(lights.Count, Allocator.Temp);
  281. // This case should never happen, but if it does it may cause an infinite loop later.
  282. if (maxShadowLightCount < 1)
  283. {
  284. Debug.LogError("maxShadowLightCount cannot be less than 1");
  285. return;
  286. }
  287. // Determine last light with volumetric shadows to be rendered if we want to use a different store action after using rendering its volumetric shadows
  288. int useFinalStoreActionAfter = lights.Count;
  289. if (intermediateStoreAction != finalStoreAction)
  290. {
  291. for (int i = lights.Count - 1; i >= 0; i--)
  292. {
  293. if (lights[i].renderVolumetricShadows)
  294. {
  295. useFinalStoreActionAfter = i;
  296. break;
  297. }
  298. }
  299. }
  300. // Break up light rendering into batches for the purpose of shadow casting
  301. var lightIndex = 0;
  302. while (lightIndex < lights.Count)
  303. {
  304. var remainingLights = (uint)lights.Count - lightIndex;
  305. var batchedLights = 0;
  306. // Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
  307. var shadowLightCount = 0;
  308. while (batchedLights < remainingLights && shadowLightCount < maxShadowLightCount)
  309. {
  310. int curLightIndex = lightIndex + batchedLights;
  311. var light = lights[curLightIndex];
  312. if (CanCastVolumetricShadows(light, layer.endLayerValue))
  313. {
  314. doesLightAtIndexHaveShadows[curLightIndex] = false;
  315. if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, ref layer, light, shadowLightCount, light.shadowVolumeIntensity))
  316. {
  317. doesLightAtIndexHaveShadows[curLightIndex] = true;
  318. shadowLightCount++;
  319. }
  320. }
  321. batchedLights++;
  322. }
  323. // Set the current RT to the light RT
  324. if (shadowLightCount > 0 || requiresRTInit)
  325. {
  326. var storeAction = lightIndex + batchedLights >= useFinalStoreActionAfter ? finalStoreAction : intermediateStoreAction;
  327. cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, storeAction, depthTexture, RenderBufferLoadAction.Load, storeAction);
  328. requiresRTInit = false;
  329. }
  330. // Render all the lights.
  331. shadowLightCount = 0;
  332. for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
  333. {
  334. var arrayIndex = (int)(lightIndex + lightIndexOffset);
  335. var light = lights[arrayIndex];
  336. if (light.volumeIntensity <= 0.0f || !light.volumetricEnabled)
  337. continue;
  338. if (layer.endLayerValue == light.GetTopMostLitLayer()) // this implies the layer is correct
  339. RenderLight(pass, cmd, light, true, light.blendStyleIndex, layer.startLayerID, doesLightAtIndexHaveShadows[arrayIndex], LightBatch.isBatchingSupported, ref shadowLightCount);
  340. }
  341. lightBatch.Flush(CommandBufferHelpers.GetRasterCommandBuffer(cmd));
  342. // Release all of the temporary shadow textures
  343. for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
  344. ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
  345. lightIndex += batchedLights;
  346. }
  347. doesLightAtIndexHaveShadows.Dispose();
  348. }
  349. // TODO: Remove once Rendergraph becomes default pipeline
  350. internal static void SetLightShaderGlobals(Renderer2DData rendererData, RasterCommandBuffer cmd)
  351. {
  352. for (var i = 0; i < rendererData.lightBlendStyles.Length; i++)
  353. {
  354. var blendStyle = rendererData.lightBlendStyles[i];
  355. if (i >= k_BlendFactorsPropIDs.Length)
  356. break;
  357. cmd.SetGlobalVector(k_BlendFactorsPropIDs[i], blendStyle.blendFactors);
  358. cmd.SetGlobalVector(k_MaskFilterPropIDs[i], blendStyle.maskTextureChannelFilter.mask);
  359. cmd.SetGlobalVector(k_InvertedFilterPropIDs[i], blendStyle.maskTextureChannelFilter.inverted);
  360. }
  361. }
  362. internal static void SetLightShaderGlobals(RasterCommandBuffer cmd, Light2DBlendStyle[] lightBlendStyles, int[] blendStyleIndices)
  363. {
  364. for (var i = 0; i < blendStyleIndices.Length; i++)
  365. {
  366. var blendStyle = lightBlendStyles[blendStyleIndices[i]];
  367. if (i >= k_BlendFactorsPropIDs.Length)
  368. break;
  369. cmd.SetGlobalVector(k_BlendFactorsPropIDs[i], blendStyle.blendFactors);
  370. cmd.SetGlobalVector(k_MaskFilterPropIDs[i], blendStyle.maskTextureChannelFilter.mask);
  371. cmd.SetGlobalVector(k_InvertedFilterPropIDs[i], blendStyle.maskTextureChannelFilter.inverted);
  372. }
  373. }
  374. private static float GetNormalizedInnerRadius(Light2D light)
  375. {
  376. return light.pointLightInnerRadius / light.pointLightOuterRadius;
  377. }
  378. private static float GetNormalizedAngle(float angle)
  379. {
  380. return (angle / 360.0f);
  381. }
  382. private static void GetScaledLightInvMatrix(Light2D light, out Matrix4x4 retMatrix)
  383. {
  384. var outerRadius = light.pointLightOuterRadius;
  385. var lightScale = Vector3.one;
  386. var outerRadiusScale = new Vector3(lightScale.x * outerRadius, lightScale.y * outerRadius, lightScale.z * outerRadius);
  387. var transform = light.transform;
  388. var scaledLightMat = Matrix4x4.TRS(transform.position, transform.rotation, outerRadiusScale);
  389. retMatrix = Matrix4x4.Inverse(scaledLightMat);
  390. }
  391. internal static void SetPerLightShaderGlobals(IRasterCommandBuffer cmd, Light2D light, int slot, bool isVolumetric, bool hasShadows, bool batchingSupported)
  392. {
  393. float intensity = light.intensity * light.color.a;
  394. Color color = intensity * light.color;
  395. color.a = 1.0f;
  396. float volumeIntensity = light.volumetricEnabled ? light.volumeIntensity : 1.0f;
  397. if (batchingSupported)
  398. {
  399. // Batched Params.
  400. PerLight2D perLight = lightBatch.GetLight(slot);
  401. perLight.Position = new float4(light.transform.position, light.normalMapDistance);
  402. perLight.FalloffIntensity = light.falloffIntensity;
  403. perLight.FalloffDistance = light.shapeLightFalloffSize;
  404. perLight.Color = new float4(color.r, color.g, color.b, color.a);
  405. perLight.VolumeOpacity = volumeIntensity;
  406. perLight.LightType = (int)light.lightType;
  407. perLight.ShadowIntensity = 1.0f;
  408. if (hasShadows)
  409. perLight.ShadowIntensity = isVolumetric ? (1 - light.shadowVolumeIntensity) : (1 - light.shadowIntensity);
  410. lightBatch.SetLight(slot, perLight);
  411. }
  412. else
  413. {
  414. cmd.SetGlobalVector(k_L2DPosition, new float4(light.transform.position, light.normalMapDistance));
  415. cmd.SetGlobalFloat(k_L2DFalloffIntensity, light.falloffIntensity);
  416. cmd.SetGlobalFloat(k_L2DFalloffDistance, light.shapeLightFalloffSize);
  417. cmd.SetGlobalColor(k_L2DColor, color);
  418. cmd.SetGlobalFloat(k_L2DVolumeOpacity, volumeIntensity);
  419. cmd.SetGlobalInt(k_L2DLightType, (int)light.lightType);
  420. cmd.SetGlobalFloat(k_L2DShadowIntensity, hasShadows ? (isVolumetric ? (1 - light.shadowVolumeIntensity) : (1 - light.shadowIntensity)) : 1);
  421. }
  422. if (hasShadows)
  423. ShadowRendering.SetGlobalShadowProp(cmd);
  424. }
  425. internal static void SetPerPointLightShaderGlobals(IRasterCommandBuffer cmd, Light2D light, int slot, bool batchingSupported)
  426. {
  427. // This is used for the lookup texture
  428. GetScaledLightInvMatrix(light, out var lightInverseMatrix);
  429. var innerRadius = GetNormalizedInnerRadius(light);
  430. var innerAngle = GetNormalizedAngle(light.pointLightInnerAngle);
  431. var outerAngle = GetNormalizedAngle(light.pointLightOuterAngle);
  432. var innerRadiusMult = 1 / (1 - innerRadius);
  433. if (batchingSupported)
  434. {
  435. // Batched Params.
  436. PerLight2D perLight = lightBatch.GetLight(slot);
  437. perLight.InvMatrix = new float4x4(lightInverseMatrix.GetColumn(0), lightInverseMatrix.GetColumn(1), lightInverseMatrix.GetColumn(2), lightInverseMatrix.GetColumn(3));
  438. perLight.InnerRadiusMult = innerRadiusMult;
  439. perLight.InnerAngle = innerAngle;
  440. perLight.OuterAngle = outerAngle;
  441. lightBatch.SetLight(slot, perLight);
  442. }
  443. else
  444. {
  445. cmd.SetGlobalMatrix(k_L2DInvMatrix, lightInverseMatrix);
  446. cmd.SetGlobalFloat(k_L2DInnerRadiusMult, innerRadiusMult);
  447. cmd.SetGlobalFloat(k_L2DInnerAngle, innerAngle);
  448. cmd.SetGlobalFloat(k_L2DOuterAngle, outerAngle);
  449. }
  450. }
  451. // TODO: Remove once Rendergraph becomes default pipeline
  452. internal static bool SetCookieShaderGlobals(CommandBuffer cmd, Light2D light)
  453. {
  454. if (light.useCookieSprite)
  455. cmd.SetGlobalTexture(light.lightType == Light2D.LightType.Sprite ? k_CookieTexID : k_PointLightCookieTexID, light.lightCookieSprite.texture);
  456. return light.useCookieSprite;
  457. }
  458. internal static void SetCookieShaderProperties(Light2D light, MaterialPropertyBlock properties)
  459. {
  460. if (light.useCookieSprite && light.m_CookieSpriteTextureHandle.IsValid())
  461. properties.SetTexture(light.lightType == Light2D.LightType.Sprite ? k_CookieTexID : k_PointLightCookieTexID, light.m_CookieSpriteTextureHandle);
  462. }
  463. public static void ClearDirtyLighting(this IRenderPass2D pass, CommandBuffer cmd, uint blendStylesUsed)
  464. {
  465. for (var i = 0; i < pass.rendererData.lightBlendStyles.Length; ++i)
  466. {
  467. if ((blendStylesUsed & (uint)(1 << i)) == 0)
  468. continue;
  469. if (!pass.rendererData.lightBlendStyles[i].isDirty)
  470. continue;
  471. CoreUtils.SetRenderTarget(cmd, pass.rendererData.lightBlendStyles[i].renderTargetHandle, ClearFlag.Color, Color.black);
  472. pass.rendererData.lightBlendStyles[i].isDirty = false;
  473. }
  474. }
  475. internal static void RenderNormals(this IRenderPass2D pass, ScriptableRenderContext context, RenderingData renderingData, DrawingSettings drawSettings, FilteringSettings filterSettings, RTHandle depthTarget, ref bool bFirstClear)
  476. {
  477. var cmd = renderingData.commandBuffer;
  478. using (new ProfilingScope(cmd, m_ProfilingSampler))
  479. {
  480. // figure out the scale
  481. var normalRTScale = 0.0f;
  482. if (depthTarget != null)
  483. normalRTScale = 1.0f;
  484. else
  485. normalRTScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
  486. pass.CreateNormalMapRenderTexture(renderingData, cmd, normalRTScale);
  487. var msaaEnabled = renderingData.cameraData.cameraTargetDescriptor.msaaSamples > 1;
  488. var storeAction = msaaEnabled ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.Store;
  489. var clearFlag = pass.rendererData.useDepthStencilBuffer ? ClearFlag.All : ClearFlag.Color;
  490. clearFlag = bFirstClear ? clearFlag : ClearFlag.Color;
  491. bFirstClear = false;
  492. if (depthTarget != null)
  493. {
  494. CoreUtils.SetRenderTarget(cmd,
  495. pass.rendererData.normalsRenderTarget, RenderBufferLoadAction.DontCare, storeAction,
  496. depthTarget, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store,
  497. clearFlag, k_NormalClearColor);
  498. }
  499. else
  500. CoreUtils.SetRenderTarget(cmd, pass.rendererData.normalsRenderTarget, RenderBufferLoadAction.DontCare, storeAction, clearFlag, k_NormalClearColor);
  501. context.ExecuteCommandBuffer(cmd);
  502. cmd.Clear();
  503. drawSettings.SetShaderPassName(0, k_NormalsRenderingPassName);
  504. var param = new RendererListParams(renderingData.cullResults, drawSettings, filterSettings);
  505. var rl = context.CreateRendererList(ref param);
  506. cmd.DrawRendererList(rl);
  507. }
  508. }
  509. public static void RenderLights(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, ref LayerBatch layerBatch, ref RenderTextureDescriptor rtDesc)
  510. {
  511. // Before rendering the lights cache some values that are expensive to get/calculate
  512. var culledLights = pass.rendererData.lightCullResult.visibleLights;
  513. for (var i = 0; i < culledLights.Count; i++)
  514. {
  515. culledLights[i].CacheValues();
  516. }
  517. ShadowCasterGroup2DManager.CacheValues();
  518. var blendStyles = pass.rendererData.lightBlendStyles;
  519. for (var i = 0; i < blendStyles.Length; ++i)
  520. {
  521. if ((layerBatch.lightStats.blendStylesUsed & (uint)(1 << i)) == 0)
  522. continue;
  523. var sampleName = blendStyles[i].name;
  524. cmd.BeginSample(sampleName);
  525. if (!Light2DManager.GetGlobalColor(layerBatch.startLayerID, i, out var clearColor))
  526. clearColor = Color.black;
  527. var anyLights = (layerBatch.lightStats.blendStylesWithLights & (uint)(1 << i)) != 0;
  528. var desc = rtDesc;
  529. if (!anyLights) // No lights -- create tiny texture
  530. desc.width = desc.height = 4;
  531. var identifier = layerBatch.GetRTId(cmd, desc, i);
  532. cmd.SetRenderTarget(identifier,
  533. RenderBufferLoadAction.DontCare,
  534. RenderBufferStoreAction.Store,
  535. RenderBufferLoadAction.DontCare,
  536. RenderBufferStoreAction.DontCare);
  537. cmd.ClearRenderTarget(false, true, clearColor);
  538. if (anyLights)
  539. {
  540. RenderLightSet(
  541. pass, renderingData,
  542. i,
  543. cmd,
  544. ref layerBatch,
  545. identifier,
  546. pass.rendererData.lightCullResult.visibleLights
  547. );
  548. }
  549. cmd.EndSample(sampleName);
  550. }
  551. }
  552. private static void SetBlendModes(Material material, BlendMode src, BlendMode dst)
  553. {
  554. material.SetFloat(k_SrcBlendID, (float)src);
  555. material.SetFloat(k_DstBlendID, (float)dst);
  556. }
  557. private static uint GetLightMaterialIndex(Light2D light, bool isVolume)
  558. {
  559. var isPoint = light.isPointLight;
  560. var bitIndex = 0;
  561. var volumeBit = isVolume ? 1u << bitIndex : 0u;
  562. bitIndex++;
  563. var shapeBit = (isVolume && !isPoint) ? 1u << bitIndex : 0u;
  564. bitIndex++;
  565. var additiveBit = light.overlapOperation == Light2D.OverlapOperation.AlphaBlend ? 0u : 1u << bitIndex;
  566. bitIndex++;
  567. var pointCookieBit = (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null) ? 1u << bitIndex : 0u;
  568. bitIndex++;
  569. var fastQualityBit = (light.normalMapQuality == Light2D.NormalMapQuality.Fast) ? 1u << bitIndex : 0u;
  570. bitIndex++;
  571. var useNormalMap = light.normalMapQuality != Light2D.NormalMapQuality.Disabled ? 1u << bitIndex : 0u;
  572. return fastQualityBit | pointCookieBit | additiveBit | shapeBit | volumeBit | useNormalMap;
  573. }
  574. private static Material CreateLightMaterial(Renderer2DData rendererData, Light2D light, bool isVolume)
  575. {
  576. if (!GraphicsSettings.TryGetRenderPipelineSettings<Renderer2DResources>(out var resources))
  577. return null;
  578. var isPoint = light.isPointLight;
  579. Material material = CoreUtils.CreateEngineMaterial(resources.lightShader);
  580. if (!isVolume)
  581. {
  582. if (light.overlapOperation == Light2D.OverlapOperation.Additive)
  583. {
  584. SetBlendModes(material, BlendMode.One, BlendMode.One);
  585. material.EnableKeyword(k_UseAdditiveBlendingKeyword);
  586. }
  587. else
  588. SetBlendModes(material, BlendMode.SrcAlpha, BlendMode.OneMinusSrcAlpha);
  589. }
  590. else
  591. {
  592. material.EnableKeyword(k_UseVolumetric);
  593. if (light.lightType == Light2D.LightType.Point)
  594. SetBlendModes(material, BlendMode.One, BlendMode.One);
  595. else
  596. {
  597. material.SetInt("_HandleZTest", (int)CompareFunction.Disabled);
  598. SetBlendModes(material, BlendMode.SrcAlpha, BlendMode.One);
  599. }
  600. }
  601. if (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
  602. material.EnableKeyword(k_UsePointLightCookiesKeyword);
  603. if (light.normalMapQuality == Light2D.NormalMapQuality.Fast)
  604. material.EnableKeyword(k_LightQualityFastKeyword);
  605. if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled)
  606. material.EnableKeyword(k_UseNormalMap);
  607. return material;
  608. }
  609. public static Material GetLightMaterial(this Renderer2DData rendererData, Light2D light, bool isVolume)
  610. {
  611. var materialIndex = GetLightMaterialIndex(light, isVolume);
  612. if (!rendererData.lightMaterials.TryGetValue(materialIndex, out var material))
  613. {
  614. material = CreateLightMaterial(rendererData, light, isVolume);
  615. rendererData.lightMaterials[materialIndex] = material;
  616. }
  617. return material;
  618. }
  619. }
  620. }