MainLightShadowCasterPass.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using System;
  2. namespace UnityEngine.Rendering.Universal.Internal
  3. {
  4. /// <summary>
  5. /// Renders a shadow map for the main Light.
  6. /// </summary>
  7. public class MainLightShadowCasterPass : ScriptableRenderPass
  8. {
  9. private static class MainLightShadowConstantBuffer
  10. {
  11. public static int _WorldToShadow;
  12. public static int _ShadowParams;
  13. public static int _CascadeShadowSplitSpheres0;
  14. public static int _CascadeShadowSplitSpheres1;
  15. public static int _CascadeShadowSplitSpheres2;
  16. public static int _CascadeShadowSplitSpheres3;
  17. public static int _CascadeShadowSplitSphereRadii;
  18. public static int _ShadowOffset0;
  19. public static int _ShadowOffset1;
  20. public static int _ShadowOffset2;
  21. public static int _ShadowOffset3;
  22. public static int _ShadowmapSize;
  23. }
  24. const int k_MaxCascades = 4;
  25. const int k_ShadowmapBufferBits = 16;
  26. int m_ShadowmapWidth;
  27. int m_ShadowmapHeight;
  28. int m_ShadowCasterCascadesCount;
  29. bool m_SupportsBoxFilterForShadows;
  30. RenderTargetHandle m_MainLightShadowmap;
  31. RenderTexture m_MainLightShadowmapTexture;
  32. Matrix4x4[] m_MainLightShadowMatrices;
  33. ShadowSliceData[] m_CascadeSlices;
  34. Vector4[] m_CascadeSplitDistances;
  35. const string m_ProfilerTag = "Render Main Shadowmap";
  36. ProfilingSampler m_ProfilingSampler = new ProfilingSampler(m_ProfilerTag);
  37. public MainLightShadowCasterPass(RenderPassEvent evt)
  38. {
  39. renderPassEvent = evt;
  40. m_MainLightShadowMatrices = new Matrix4x4[k_MaxCascades + 1];
  41. m_CascadeSlices = new ShadowSliceData[k_MaxCascades];
  42. m_CascadeSplitDistances = new Vector4[k_MaxCascades];
  43. MainLightShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_MainLightWorldToShadow");
  44. MainLightShadowConstantBuffer._ShadowParams = Shader.PropertyToID("_MainLightShadowParams");
  45. MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0 = Shader.PropertyToID("_CascadeShadowSplitSpheres0");
  46. MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1 = Shader.PropertyToID("_CascadeShadowSplitSpheres1");
  47. MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2 = Shader.PropertyToID("_CascadeShadowSplitSpheres2");
  48. MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3 = Shader.PropertyToID("_CascadeShadowSplitSpheres3");
  49. MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii = Shader.PropertyToID("_CascadeShadowSplitSphereRadii");
  50. MainLightShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_MainLightShadowOffset0");
  51. MainLightShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_MainLightShadowOffset1");
  52. MainLightShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_MainLightShadowOffset2");
  53. MainLightShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_MainLightShadowOffset3");
  54. MainLightShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_MainLightShadowmapSize");
  55. m_MainLightShadowmap.Init("_MainLightShadowmapTexture");
  56. m_SupportsBoxFilterForShadows = Application.isMobilePlatform || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Switch;
  57. }
  58. public bool Setup(ref RenderingData renderingData)
  59. {
  60. if (!renderingData.shadowData.supportsMainLightShadows)
  61. return false;
  62. Clear();
  63. int shadowLightIndex = renderingData.lightData.mainLightIndex;
  64. if (shadowLightIndex == -1)
  65. return false;
  66. VisibleLight shadowLight = renderingData.lightData.visibleLights[shadowLightIndex];
  67. Light light = shadowLight.light;
  68. if (light.shadows == LightShadows.None)
  69. return false;
  70. if (shadowLight.lightType != LightType.Directional)
  71. {
  72. Debug.LogWarning("Only directional lights are supported as main light.");
  73. }
  74. Bounds bounds;
  75. if (!renderingData.cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
  76. return false;
  77. m_ShadowCasterCascadesCount = renderingData.shadowData.mainLightShadowCascadesCount;
  78. int shadowResolution = ShadowUtils.GetMaxTileResolutionInAtlas(renderingData.shadowData.mainLightShadowmapWidth,
  79. renderingData.shadowData.mainLightShadowmapHeight, m_ShadowCasterCascadesCount);
  80. m_ShadowmapWidth = renderingData.shadowData.mainLightShadowmapWidth;
  81. m_ShadowmapHeight = (m_ShadowCasterCascadesCount == 2) ?
  82. renderingData.shadowData.mainLightShadowmapHeight >> 1 :
  83. renderingData.shadowData.mainLightShadowmapHeight;
  84. for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
  85. {
  86. bool success = ShadowUtils.ExtractDirectionalLightMatrix(ref renderingData.cullResults, ref renderingData.shadowData,
  87. shadowLightIndex, cascadeIndex, m_ShadowmapWidth, m_ShadowmapHeight, shadowResolution, light.shadowNearPlane,
  88. out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex], out m_CascadeSlices[cascadeIndex].viewMatrix, out m_CascadeSlices[cascadeIndex].projectionMatrix);
  89. if (!success)
  90. return false;
  91. }
  92. return true;
  93. }
  94. public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
  95. {
  96. m_MainLightShadowmapTexture = ShadowUtils.GetTemporaryShadowTexture(m_ShadowmapWidth,
  97. m_ShadowmapHeight, k_ShadowmapBufferBits);
  98. ConfigureTarget(new RenderTargetIdentifier(m_MainLightShadowmapTexture));
  99. ConfigureClear(ClearFlag.All, Color.black);
  100. }
  101. /// <inheritdoc/>
  102. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  103. {
  104. RenderMainLightCascadeShadowmap(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);
  105. }
  106. /// <inheritdoc/>
  107. public override void FrameCleanup(CommandBuffer cmd)
  108. {
  109. if (cmd == null)
  110. throw new ArgumentNullException("cmd");
  111. if (m_MainLightShadowmapTexture)
  112. {
  113. RenderTexture.ReleaseTemporary(m_MainLightShadowmapTexture);
  114. m_MainLightShadowmapTexture = null;
  115. }
  116. }
  117. void Clear()
  118. {
  119. m_MainLightShadowmapTexture = null;
  120. for (int i = 0; i < m_MainLightShadowMatrices.Length; ++i)
  121. m_MainLightShadowMatrices[i] = Matrix4x4.identity;
  122. for (int i = 0; i < m_CascadeSplitDistances.Length; ++i)
  123. m_CascadeSplitDistances[i] = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
  124. for (int i = 0; i < m_CascadeSlices.Length; ++i)
  125. m_CascadeSlices[i].Clear();
  126. }
  127. void RenderMainLightCascadeShadowmap(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData)
  128. {
  129. int shadowLightIndex = lightData.mainLightIndex;
  130. if (shadowLightIndex == -1)
  131. return;
  132. VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex];
  133. CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
  134. using (new ProfilingScope(cmd, m_ProfilingSampler))
  135. {
  136. var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex);
  137. for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
  138. {
  139. var splitData = settings.splitData;
  140. splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex];
  141. settings.splitData = splitData;
  142. Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution);
  143. ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);
  144. ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex],
  145. ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix);
  146. }
  147. bool softShadows = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows;
  148. CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, true);
  149. CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
  150. CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows);
  151. SetupMainLightShadowReceiverConstants(cmd, shadowLight, softShadows);
  152. }
  153. context.ExecuteCommandBuffer(cmd);
  154. CommandBufferPool.Release(cmd);
  155. }
  156. void SetupMainLightShadowReceiverConstants(CommandBuffer cmd, VisibleLight shadowLight, bool softShadows)
  157. {
  158. Light light = shadowLight.light;
  159. int cascadeCount = m_ShadowCasterCascadesCount;
  160. for (int i = 0; i < cascadeCount; ++i)
  161. m_MainLightShadowMatrices[i] = m_CascadeSlices[i].shadowTransform;
  162. // We setup and additional a no-op WorldToShadow matrix in the last index
  163. // because the ComputeCascadeIndex function in Shadows.hlsl can return an index
  164. // out of bounds. (position not inside any cascade) and we want to avoid branching
  165. Matrix4x4 noOpShadowMatrix = Matrix4x4.zero;
  166. noOpShadowMatrix.m22 = (SystemInfo.usesReversedZBuffer) ? 1.0f : 0.0f;
  167. for (int i = cascadeCount; i <= k_MaxCascades; ++i)
  168. m_MainLightShadowMatrices[i] = noOpShadowMatrix;
  169. float invShadowAtlasWidth = 1.0f / m_ShadowmapWidth;
  170. float invShadowAtlasHeight = 1.0f / m_ShadowmapHeight;
  171. float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth;
  172. float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight;
  173. float softShadowsProp = softShadows ? 1.0f : 0.0f;
  174. cmd.SetGlobalTexture(m_MainLightShadowmap.id, m_MainLightShadowmapTexture);
  175. cmd.SetGlobalMatrixArray(MainLightShadowConstantBuffer._WorldToShadow, m_MainLightShadowMatrices);
  176. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowParams, new Vector4(light.shadowStrength, softShadowsProp, 0.0f, 0.0f));
  177. if (m_ShadowCasterCascadesCount > 1)
  178. {
  179. cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0,
  180. m_CascadeSplitDistances[0]);
  181. cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1,
  182. m_CascadeSplitDistances[1]);
  183. cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2,
  184. m_CascadeSplitDistances[2]);
  185. cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3,
  186. m_CascadeSplitDistances[3]);
  187. cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii, new Vector4(
  188. m_CascadeSplitDistances[0].w * m_CascadeSplitDistances[0].w,
  189. m_CascadeSplitDistances[1].w * m_CascadeSplitDistances[1].w,
  190. m_CascadeSplitDistances[2].w * m_CascadeSplitDistances[2].w,
  191. m_CascadeSplitDistances[3].w * m_CascadeSplitDistances[3].w));
  192. }
  193. if (softShadows)
  194. {
  195. if (m_SupportsBoxFilterForShadows)
  196. {
  197. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset0,
  198. new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
  199. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset1,
  200. new Vector4(invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
  201. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset2,
  202. new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
  203. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset3,
  204. new Vector4(invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
  205. }
  206. // Currently only used when !SHADER_API_MOBILE but risky to not set them as it's generic
  207. // enough so custom shaders might use it.
  208. cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowAtlasWidth,
  209. invShadowAtlasHeight,
  210. m_ShadowmapWidth, m_ShadowmapHeight));
  211. }
  212. }
  213. };
  214. }