Brak opisu
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.

ShadowCulling.cs 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System;
  2. using Unity.Collections;
  3. namespace UnityEngine.Rendering.Universal
  4. {
  5. internal struct URPLightShadowCullingInfos
  6. {
  7. public NativeArray<ShadowSliceData> slices;
  8. public uint slicesValidMask;
  9. public readonly bool IsSliceValid(int i) => (slicesValidMask & (1 << i)) != 0;
  10. }
  11. internal static class ShadowCulling
  12. {
  13. static readonly ProfilingSampler computeShadowCasterCullingInfosMarker = new ProfilingSampler($"{nameof(UniversalRenderPipeline)}.{nameof(ComputeShadowCasterCullingInfos)}");
  14. public static NativeArray<URPLightShadowCullingInfos> CullShadowCasters(ref ScriptableRenderContext context,
  15. UniversalShadowData shadowData,
  16. ref AdditionalLightsShadowAtlasLayout shadowAtlasLayout,
  17. ref CullingResults cullResults)
  18. {
  19. ShadowCastersCullingInfos shadowCullingInfos;
  20. NativeArray<URPLightShadowCullingInfos> urpVisibleLightsShadowCullingInfos;
  21. ComputeShadowCasterCullingInfos(shadowData, ref shadowAtlasLayout, ref cullResults, out shadowCullingInfos, out urpVisibleLightsShadowCullingInfos);
  22. context.CullShadowCasters(cullResults, shadowCullingInfos);
  23. return urpVisibleLightsShadowCullingInfos;
  24. }
  25. static void ComputeShadowCasterCullingInfos(UniversalShadowData shadowData,
  26. ref AdditionalLightsShadowAtlasLayout shadowAtlasLayout,
  27. ref CullingResults cullingResults,
  28. out ShadowCastersCullingInfos shadowCullingInfos,
  29. out NativeArray<URPLightShadowCullingInfos> urpVisibleLightsShadowCullingInfos)
  30. {
  31. const int MaxShadowSplitCount = 6;
  32. using var profScope = new ProfilingScope(computeShadowCasterCullingInfosMarker);
  33. NativeArray<VisibleLight> visibleLights = cullingResults.visibleLights;
  34. NativeArray<ShadowSplitData> splitBuffer = new NativeArray<ShadowSplitData>(visibleLights.Length * MaxShadowSplitCount, Allocator.Temp);
  35. NativeArray<LightShadowCasterCullingInfo> perLightInfos = new NativeArray<LightShadowCasterCullingInfo>(visibleLights.Length, Allocator.Temp);
  36. urpVisibleLightsShadowCullingInfos = new NativeArray<URPLightShadowCullingInfos>(visibleLights.Length, Allocator.Temp);
  37. int totalSplitCount = 0;
  38. int splitBufferOffset = 0;
  39. for (int lightIndex = 0; lightIndex < visibleLights.Length; ++lightIndex)
  40. {
  41. ref VisibleLight visibleLight = ref cullingResults.visibleLights.UnsafeElementAt(lightIndex);
  42. LightType lightType = visibleLight.lightType;
  43. NativeArray<ShadowSliceData> slices = default;
  44. uint slicesValidMask = 0;
  45. if (lightType == LightType.Directional)
  46. {
  47. if (!shadowData.supportsMainLightShadows)
  48. continue;
  49. int splitCount = shadowData.mainLightShadowCascadesCount;
  50. int renderTargetWidth = shadowData.mainLightRenderTargetWidth;
  51. int renderTargetHeight = shadowData.mainLightRenderTargetHeight;
  52. int shadowResolution = shadowData.mainLightShadowResolution;
  53. slices = new NativeArray<ShadowSliceData>(splitCount, Allocator.Temp);
  54. slicesValidMask = 0;
  55. for (int i = 0; i < splitCount; ++i)
  56. {
  57. ShadowSliceData slice = default;
  58. bool isValid = ShadowUtils.ExtractDirectionalLightMatrix(ref cullingResults, shadowData,
  59. lightIndex, i, renderTargetWidth, renderTargetHeight, shadowResolution, visibleLight.light.shadowNearPlane,
  60. out _, // Vector4 cascadeSplitDistance. This is basically just the culling sphere which is already present in ShadowSplitData
  61. out slice);
  62. if (isValid)
  63. slicesValidMask |= 1u << i;
  64. slices[i] = slice;
  65. splitBuffer[splitBufferOffset + i] = slice.splitData;
  66. }
  67. }
  68. else if (lightType == LightType.Point)
  69. {
  70. if (!shadowData.supportsAdditionalLightShadows || !shadowAtlasLayout.HasSpaceForLight(lightIndex))
  71. continue;
  72. int splitCount = ShadowUtils.GetPunctualLightShadowSlicesCount(lightType);
  73. int sliceResolution = shadowAtlasLayout.GetSliceShadowResolutionRequest(lightIndex, 0).allocatedResolution;
  74. bool shadowFiltering = visibleLight.light.shadows == LightShadows.Soft;
  75. // Note: the same fovBias will also be used to compute ShadowUtils.GetShadowBias
  76. float fovBias = Internal.AdditionalLightsShadowCasterPass.GetPointLightShadowFrustumFovBiasInDegrees(sliceResolution, shadowFiltering);
  77. slices = new NativeArray<ShadowSliceData>(splitCount, Allocator.Temp);
  78. slicesValidMask = 0;
  79. for (int i = 0; i < splitCount; ++i)
  80. {
  81. ShadowSliceData slice = default;
  82. bool isValid = ShadowUtils.ExtractPointLightMatrix(ref cullingResults,
  83. shadowData,
  84. lightIndex,
  85. (CubemapFace)i,
  86. fovBias,
  87. out slice.shadowTransform,
  88. out slice.viewMatrix,
  89. out slice.projectionMatrix,
  90. out slice.splitData);
  91. if (isValid)
  92. slicesValidMask |= 1u << i;
  93. slices[i] = slice;
  94. splitBuffer[splitBufferOffset + i] = slice.splitData;
  95. }
  96. }
  97. else if (lightType == LightType.Spot)
  98. {
  99. if (!shadowData.supportsAdditionalLightShadows || !shadowAtlasLayout.HasSpaceForLight(lightIndex))
  100. continue;
  101. slices = new NativeArray<ShadowSliceData>(1, Allocator.Temp);
  102. slicesValidMask = 0;
  103. ShadowSliceData slice = default;
  104. bool isValid = ShadowUtils.ExtractSpotLightMatrix(ref cullingResults,
  105. shadowData,
  106. lightIndex,
  107. out slice.shadowTransform,
  108. out slice.viewMatrix,
  109. out slice.projectionMatrix,
  110. out slice.splitData);
  111. if (isValid)
  112. slicesValidMask |= 1u << 0;
  113. slices[0] = slice;
  114. splitBuffer[splitBufferOffset + 0] = slice.splitData;
  115. }
  116. URPLightShadowCullingInfos infos = default;
  117. infos.slices = slices;
  118. infos.slicesValidMask = slicesValidMask;
  119. urpVisibleLightsShadowCullingInfos[lightIndex] = infos;
  120. perLightInfos[lightIndex] = new LightShadowCasterCullingInfo
  121. {
  122. splitRange = new RangeInt(splitBufferOffset, slices.Length),
  123. projectionType = GetCullingProjectionType(lightType),
  124. };
  125. splitBufferOffset += slices.Length;
  126. totalSplitCount += slices.Length;
  127. }
  128. shadowCullingInfos = default;
  129. shadowCullingInfos.splitBuffer = splitBuffer.GetSubArray(0, totalSplitCount);
  130. shadowCullingInfos.perLightInfos = perLightInfos;
  131. }
  132. static BatchCullingProjectionType GetCullingProjectionType(LightType type)
  133. {
  134. switch (type)
  135. {
  136. case LightType.Point: return BatchCullingProjectionType.Perspective;
  137. case LightType.Spot: return BatchCullingProjectionType.Perspective;
  138. case LightType.Directional: return BatchCullingProjectionType.Orthographic;
  139. }
  140. return BatchCullingProjectionType.Unknown;
  141. }
  142. }
  143. }