Bez popisu
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.

DrawLight2DPass.cs 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Experimental.Rendering;
  4. using UnityEngine.Rendering.RenderGraphModule;
  5. using CommonResourceData = UnityEngine.Rendering.Universal.UniversalResourceData;
  6. namespace UnityEngine.Rendering.Universal
  7. {
  8. internal class DrawLight2DPass : ScriptableRenderPass
  9. {
  10. static readonly string k_LightPass = "Light2D Pass";
  11. static readonly string k_LightLowLevelPass = "Light2D LowLevelPass";
  12. static readonly string k_LightVolumetricPass = "Light2D Volumetric Pass";
  13. private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler(k_LightPass);
  14. internal static readonly ProfilingSampler m_ProfilingSamplerLowLevel = new ProfilingSampler(k_LightLowLevelPass);
  15. private static readonly ProfilingSampler m_ProfilingSamplerVolume = new ProfilingSampler(k_LightVolumetricPass);
  16. internal static readonly int k_InverseHDREmulationScaleID = Shader.PropertyToID("_InverseHDREmulationScale");
  17. internal static readonly string k_NormalMapID = "_NormalMap";
  18. internal static readonly string k_ShadowMapID = "_ShadowTex";
  19. internal static readonly string k_LightLookupID = "_LightLookup";
  20. internal static readonly string k_FalloffLookupID = "_FalloffLookup";
  21. TextureHandle[] intermediateTexture = new TextureHandle[1];
  22. internal static RTHandle m_FallOffRTHandle = null;
  23. internal static RTHandle m_LightLookupRTHandle = null;
  24. private int lightLookupInstanceID;
  25. private int fallOffLookupInstanceID;
  26. internal static MaterialPropertyBlock s_PropertyBlock = new MaterialPropertyBlock();
  27. public void Setup(RenderGraph renderGraph, ref Renderer2DData rendererData)
  28. {
  29. // Reallocate external texture if needed
  30. var fallOffLookupTexture = Light2DLookupTexture.GetFallOffLookupTexture();
  31. if (fallOffLookupInstanceID != fallOffLookupTexture.GetInstanceID())
  32. {
  33. m_FallOffRTHandle = RTHandles.Alloc(fallOffLookupTexture);
  34. fallOffLookupInstanceID = fallOffLookupTexture.GetInstanceID();
  35. }
  36. var lightLookupTexture = Light2DLookupTexture.GetLightLookupTexture();
  37. if (lightLookupInstanceID != lightLookupTexture.GetInstanceID())
  38. {
  39. m_LightLookupRTHandle = RTHandles.Alloc(lightLookupTexture);
  40. lightLookupInstanceID = lightLookupTexture.GetInstanceID();
  41. }
  42. foreach (var light in rendererData.lightCullResult.visibleLights)
  43. {
  44. if (light.useCookieSprite && light.m_CookieSpriteTexture != null)
  45. light.m_CookieSpriteTextureHandle = renderGraph.ImportTexture(light.m_CookieSpriteTexture);
  46. }
  47. }
  48. public void Dispose()
  49. {
  50. m_FallOffRTHandle?.Release();
  51. m_LightLookupRTHandle?.Release();
  52. }
  53. [Obsolete(DeprecationMessage.CompatibilityScriptingAPIObsolete, false)]
  54. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  55. {
  56. throw new NotImplementedException();
  57. }
  58. private static void Execute(RasterCommandBuffer cmd, PassData passData, ref LayerBatch layerBatch)
  59. {
  60. cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / passData.rendererData.hdrEmulationScale);
  61. for (var i = 0; i < layerBatch.activeBlendStylesIndices.Length; ++i)
  62. {
  63. var blendStyleIndex = layerBatch.activeBlendStylesIndices[i];
  64. var blendOpName = passData.rendererData.lightBlendStyles[blendStyleIndex].name;
  65. cmd.BeginSample(blendOpName);
  66. if (!passData.isVolumetric)
  67. RendererLighting.EnableBlendStyle(cmd, i, true);
  68. var lights = passData.layerBatch.lights;
  69. for (int j = 0; j < lights.Count; ++j)
  70. {
  71. var light = lights[j];
  72. // Check if light is valid
  73. if (light == null ||
  74. light.lightType == Light2D.LightType.Global ||
  75. light.blendStyleIndex != blendStyleIndex)
  76. continue;
  77. // Check if light is volumetric
  78. if (passData.isVolumetric &&
  79. (light.volumeIntensity <= 0.0f ||
  80. !light.volumetricEnabled ||
  81. layerBatch.endLayerValue != light.GetTopMostLitLayer()))
  82. continue;
  83. var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric);
  84. var lightMesh = light.lightMesh;
  85. // For Batching.
  86. var index = light.batchSlotIndex;
  87. var slotIndex = RendererLighting.lightBatch.SlotIndex(index);
  88. bool canBatch = RendererLighting.lightBatch.CanBatch(light, lightMaterial, index, out int lightHash);
  89. bool breakBatch = !canBatch;
  90. if (breakBatch && LightBatch.isBatchingSupported)
  91. RendererLighting.lightBatch.Flush(cmd);
  92. // Set material properties
  93. lightMaterial.SetTexture(k_LightLookupID, passData.lightLookUp);
  94. lightMaterial.SetTexture(k_FalloffLookupID, passData.fallOffLookUp);
  95. if (passData.layerBatch.lightStats.useNormalMap)
  96. s_PropertyBlock.SetTexture(k_NormalMapID, passData.normalMap);
  97. if (passData.layerBatch.lightStats.useShadows)
  98. s_PropertyBlock.SetTexture(k_ShadowMapID, passData.shadowMap);
  99. if (!passData.isVolumetric || (passData.isVolumetric && light.volumetricEnabled))
  100. RendererLighting.SetCookieShaderProperties(light, s_PropertyBlock);
  101. // Set shader global properties
  102. RendererLighting.SetPerLightShaderGlobals(cmd, light, slotIndex, passData.isVolumetric, false, LightBatch.isBatchingSupported);
  103. if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
  104. RendererLighting.SetPerPointLightShaderGlobals(cmd, light, slotIndex, LightBatch.isBatchingSupported);
  105. if (LightBatch.isBatchingSupported)
  106. {
  107. RendererLighting.lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, index);
  108. RendererLighting.lightBatch.Flush(cmd);
  109. }
  110. else
  111. {
  112. cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial, 0, 0, s_PropertyBlock);
  113. }
  114. }
  115. RendererLighting.EnableBlendStyle(cmd, i, false);
  116. cmd.EndSample(blendOpName);
  117. }
  118. }
  119. internal static void ExecuteUnsafe(UnsafeCommandBuffer cmd, PassData passData, ref LayerBatch layerBatch, List<Light2D> lights, bool useShadows = false)
  120. {
  121. cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / passData.rendererData.hdrEmulationScale);
  122. for (var i = 0; i < layerBatch.activeBlendStylesIndices.Length; ++i)
  123. {
  124. var blendStyleIndex = layerBatch.activeBlendStylesIndices[i];
  125. var blendOpName = passData.rendererData.lightBlendStyles[blendStyleIndex].name;
  126. cmd.BeginSample(blendOpName);
  127. if (!Renderer2D.supportsMRT && !passData.isVolumetric)
  128. cmd.SetRenderTarget(passData.lightTextures[i], passData.depthTexture);
  129. var indicesIndex = Renderer2D.supportsMRT ? i : 0;
  130. if (!passData.isVolumetric)
  131. RendererLighting.EnableBlendStyle(cmd, indicesIndex, true);
  132. for (int j = 0; j < lights.Count; ++j)
  133. {
  134. var light = lights[j];
  135. // Check if light is valid
  136. if (light == null ||
  137. light.lightType == Light2D.LightType.Global ||
  138. light.blendStyleIndex != blendStyleIndex)
  139. continue;
  140. // Check if light is volumetric
  141. if (passData.isVolumetric &&
  142. (light.volumeIntensity <= 0.0f ||
  143. !light.volumetricEnabled ||
  144. layerBatch.endLayerValue != light.GetTopMostLitLayer()))
  145. continue;
  146. var lightMaterial = passData.rendererData.GetLightMaterial(light, passData.isVolumetric);
  147. var lightMesh = light.lightMesh;
  148. // For Batching.
  149. var index = light.batchSlotIndex;
  150. var slotIndex = RendererLighting.lightBatch.SlotIndex(index);
  151. bool canBatch = RendererLighting.lightBatch.CanBatch(light, lightMaterial, index, out int lightHash);
  152. //bool breakBatch = !canBatch;
  153. //if (breakBatch && LightBatch.isBatchingSupported)
  154. // RendererLighting.lightBatch.Flush(cmd);
  155. // Set material properties
  156. lightMaterial.SetTexture(k_LightLookupID, passData.lightLookUp);
  157. lightMaterial.SetTexture(k_FalloffLookupID, passData.fallOffLookUp);
  158. if (passData.layerBatch.lightStats.useNormalMap)
  159. s_PropertyBlock.SetTexture(k_NormalMapID, passData.normalMap);
  160. if (passData.layerBatch.lightStats.useShadows)
  161. s_PropertyBlock.SetTexture(k_ShadowMapID, passData.shadowMap);
  162. if (!passData.isVolumetric || (passData.isVolumetric && light.volumetricEnabled))
  163. RendererLighting.SetCookieShaderProperties(light, s_PropertyBlock);
  164. // Set shader global properties
  165. RendererLighting.SetPerLightShaderGlobals(cmd, light, slotIndex, passData.isVolumetric, useShadows, LightBatch.isBatchingSupported);
  166. if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
  167. RendererLighting.SetPerPointLightShaderGlobals(cmd, light, slotIndex, LightBatch.isBatchingSupported);
  168. if (LightBatch.isBatchingSupported)
  169. {
  170. //RendererLighting.lightBatch.AddBatch(light, lightMaterial, light.GetMatrix(), lightMesh, 0, lightHash, index);
  171. //RendererLighting.lightBatch.Flush(cmd);
  172. }
  173. else
  174. {
  175. cmd.DrawMesh(lightMesh, light.GetMatrix(), lightMaterial, 0, 0, s_PropertyBlock);
  176. }
  177. }
  178. RendererLighting.EnableBlendStyle(cmd, indicesIndex, false);
  179. cmd.EndSample(blendOpName);
  180. }
  181. }
  182. internal class PassData
  183. {
  184. internal LayerBatch layerBatch;
  185. internal Renderer2DData rendererData;
  186. internal bool isVolumetric;
  187. internal TextureHandle normalMap;
  188. internal TextureHandle shadowMap;
  189. internal TextureHandle fallOffLookUp;
  190. internal TextureHandle lightLookUp;
  191. // TODO: Optimize and remove low level pass
  192. // For low level shadow and light pass
  193. internal RenderTargetIdentifier[] lightTexturesRT;
  194. internal TextureHandle[] lightTextures;
  195. internal TextureHandle depthTexture;
  196. internal TextureHandle shadowDepth;
  197. }
  198. public void Render(RenderGraph graph, ContextContainer frameData, Renderer2DData rendererData, ref LayerBatch layerBatch, int batchIndex, bool isVolumetric = false)
  199. {
  200. Universal2DResourceData universal2DResourceData = frameData.Get<Universal2DResourceData>();
  201. CommonResourceData commonResourceData = frameData.Get<CommonResourceData>();
  202. if (!layerBatch.lightStats.useLights ||
  203. isVolumetric && !layerBatch.lightStats.useVolumetricLights)
  204. return;
  205. // OpenGL has a bug with MRTs - support single RTs by using low level pass
  206. if (!isVolumetric && Renderer2D.IsGLDevice())
  207. {
  208. using (var builder = graph.AddUnsafePass<PassData>( k_LightLowLevelPass, out var passData, m_ProfilingSamplerLowLevel))
  209. {
  210. intermediateTexture[0] = commonResourceData.activeColorTexture;
  211. passData.lightTextures = universal2DResourceData.lightTextures[batchIndex];
  212. passData.depthTexture = universal2DResourceData.intermediateDepth;
  213. for (var i = 0; i < passData.lightTextures.Length; i++)
  214. builder.UseTexture(passData.lightTextures[i], AccessFlags.Write);
  215. builder.UseTexture(passData.depthTexture, AccessFlags.Write);
  216. if (layerBatch.lightStats.useNormalMap)
  217. builder.UseTexture(universal2DResourceData.normalsTexture[batchIndex]);
  218. if (layerBatch.lightStats.useShadows)
  219. builder.UseTexture(universal2DResourceData.shadowsTexture);
  220. foreach (var light in layerBatch.lights)
  221. {
  222. if (light == null || !light.m_CookieSpriteTextureHandle.IsValid())
  223. continue;
  224. if (!isVolumetric || (isVolumetric && light.volumetricEnabled))
  225. builder.UseTexture(light.m_CookieSpriteTextureHandle);
  226. }
  227. passData.layerBatch = layerBatch;
  228. passData.rendererData = rendererData;
  229. passData.isVolumetric = isVolumetric;
  230. passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle;
  231. passData.shadowMap = layerBatch.lightStats.useShadows ? universal2DResourceData.shadowsTexture : TextureHandle.nullHandle;
  232. passData.fallOffLookUp = graph.ImportTexture(m_FallOffRTHandle);
  233. passData.lightLookUp = graph.ImportTexture(m_LightLookupRTHandle);
  234. builder.UseTexture(passData.fallOffLookUp);
  235. builder.UseTexture(passData.lightLookUp);
  236. builder.AllowPassCulling(false);
  237. builder.AllowGlobalStateModification(true);
  238. builder.SetRenderFunc((PassData data, UnsafeGraphContext context) =>
  239. {
  240. ExecuteUnsafe(context.cmd, data, ref data.layerBatch, data.layerBatch.lights);
  241. });
  242. }
  243. }
  244. // Default Raster Pass with MRTs
  245. else
  246. {
  247. using (var builder = graph.AddRasterRenderPass<PassData>(!isVolumetric ? k_LightPass : k_LightVolumetricPass, out var passData, !isVolumetric ? m_ProfilingSampler : m_ProfilingSamplerVolume))
  248. {
  249. intermediateTexture[0] = commonResourceData.activeColorTexture;
  250. var lightTextures = !isVolumetric ? universal2DResourceData.lightTextures[batchIndex] : intermediateTexture;
  251. var depthTexture = !isVolumetric ? universal2DResourceData.intermediateDepth : commonResourceData.activeDepthTexture;
  252. for (var i = 0; i < lightTextures.Length; i++)
  253. builder.SetRenderAttachment(lightTextures[i], i);
  254. builder.SetRenderAttachmentDepth(depthTexture);
  255. if (layerBatch.lightStats.useNormalMap)
  256. builder.UseTexture(universal2DResourceData.normalsTexture[batchIndex]);
  257. if (layerBatch.lightStats.useShadows)
  258. builder.UseTexture(universal2DResourceData.shadowsTexture);
  259. foreach (var light in layerBatch.lights)
  260. {
  261. if (light == null || !light.m_CookieSpriteTextureHandle.IsValid())
  262. continue;
  263. if (!isVolumetric || (isVolumetric && light.volumetricEnabled))
  264. builder.UseTexture(light.m_CookieSpriteTextureHandle);
  265. }
  266. passData.layerBatch = layerBatch;
  267. passData.rendererData = rendererData;
  268. passData.isVolumetric = isVolumetric;
  269. passData.normalMap = layerBatch.lightStats.useNormalMap ? universal2DResourceData.normalsTexture[batchIndex] : TextureHandle.nullHandle;
  270. passData.shadowMap = layerBatch.lightStats.useShadows ? universal2DResourceData.shadowsTexture : TextureHandle.nullHandle;
  271. passData.fallOffLookUp = graph.ImportTexture(m_FallOffRTHandle);
  272. passData.lightLookUp = graph.ImportTexture(m_LightLookupRTHandle);
  273. builder.UseTexture(passData.fallOffLookUp);
  274. builder.UseTexture(passData.lightLookUp);
  275. builder.AllowPassCulling(false);
  276. builder.AllowGlobalStateModification(true);
  277. builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
  278. {
  279. Execute(context.cmd, data, ref data.layerBatch);
  280. });
  281. }
  282. }
  283. }
  284. }
  285. }