ShadowMapping.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Renderer/ShadowMapping.h>
  6. #include <AnKi/Renderer/Renderer.h>
  7. #include <AnKi/Renderer/GBuffer.h>
  8. #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
  9. #include <AnKi/Renderer/Utils/GpuVisibility.h>
  10. #include <AnKi/Renderer/Utils/Drawer.h>
  11. #include <AnKi/Renderer/Utils/HzbGenerator.h>
  12. #include <AnKi/Core/App.h>
  13. #include <AnKi/Core/StatsSet.h>
  14. #include <AnKi/GpuMemory/GpuVisibleTransientMemoryPool.h>
  15. #include <AnKi/Util/Tracer.h>
  16. #include <AnKi/Scene/Components/LightComponent.h>
  17. #include <AnKi/Scene/Components/CameraComponent.h>
  18. #include <AnKi/Scene/RenderStateBucket.h>
  19. namespace anki {
  20. ANKI_SVAR(TilesAllocated, StatCategory::kRenderer, "Shadow tiles (re)allocated", StatFlag::kMainThreadUpdates)
  21. ANKI_SVAR(ShadowLightsProcessed, StatCategory::kRenderer, "Lights processed by shadows", StatFlag::kMainThreadUpdates | StatFlag::kZeroEveryFrame)
  22. class LightHash
  23. {
  24. public:
  25. class Unpacked
  26. {
  27. public:
  28. U64 m_uuid : 31;
  29. U64 m_componentIndex : 30;
  30. U64 m_faceIdx : 3;
  31. };
  32. union
  33. {
  34. Unpacked m_unpacked;
  35. U64 m_packed;
  36. };
  37. };
  38. static U64 encodeTileHash(U32 lightUuid, U32 componentIndex, U32 faceIdx)
  39. {
  40. ANKI_ASSERT(faceIdx < 6);
  41. LightHash c;
  42. c.m_unpacked.m_uuid = lightUuid;
  43. c.m_unpacked.m_componentIndex = componentIndex;
  44. c.m_unpacked.m_faceIdx = faceIdx;
  45. return c.m_packed;
  46. }
  47. static LightHash decodeTileHash(U64 hash)
  48. {
  49. LightHash c;
  50. c.m_packed = hash;
  51. return c;
  52. }
  53. Error ShadowMapping::init()
  54. {
  55. // Init RT
  56. {
  57. m_tileResolution = g_cvarRenderSmTileResolution;
  58. m_tileCountBothAxis = g_cvarRenderSmTileCountPerRowOrColumn;
  59. const TextureUsageBit usage =
  60. TextureUsageBit::kSrvPixel | TextureUsageBit::kSrvCompute | TextureUsageBit::kSrvDispatchRays | TextureUsageBit::kAllRtvDsv;
  61. TextureInitInfo texinit = getRenderer().create2DRenderTargetInitInfo(
  62. m_tileResolution * m_tileCountBothAxis, m_tileResolution * m_tileCountBothAxis, Format::kD32_Sfloat, usage, "ShadowAtlas");
  63. ClearValue clearVal;
  64. clearVal.m_colorf[0] = 1.0f;
  65. m_atlasTex = getRenderer().createAndClearRenderTarget(texinit, TextureUsageBit::kSrvPixel, clearVal);
  66. }
  67. // Tiles
  68. m_tileAlloc.init(m_tileCountBothAxis, m_tileCountBothAxis, kTileAllocHierarchyCount, true);
  69. ANKI_CHECK(loadShaderProgram("ShaderBinaries/ShadowMappingClearDepth.ankiprogbin", m_clearDepthProg, m_clearDepthGrProg));
  70. ANKI_CHECK(loadShaderProgram("ShaderBinaries/ShadowMappingVetVisibility.ankiprogbin", m_vetVisibilityProg, m_vetVisibilityGrProg));
  71. for(U32 i = 0; i < kMaxShadowCascades; ++i)
  72. {
  73. RendererString name;
  74. name.sprintf("DirLight HZB #%d", i);
  75. const U32 cascadeResolution = (m_tileResolution * (1 << (kTileAllocHierarchyCount - 1))) >> chooseDirectionalLightShadowCascadeDetail(i);
  76. UVec2 size(min(cascadeResolution, 1024u));
  77. size /= 2;
  78. m_cascadeHzbRtDescrs[i] = getRenderer().create2DRenderTargetDescription(size.x, size.y, Format::kR32_Sfloat, name);
  79. m_cascadeHzbRtDescrs[i].m_mipmapCount = computeMaxMipmapCount2d(m_cascadeHzbRtDescrs[i].m_width, m_cascadeHzbRtDescrs[i].m_height);
  80. m_cascadeHzbRtDescrs[i].bake();
  81. }
  82. return Error::kNone;
  83. }
  84. Mat4 ShadowMapping::createSpotLightTextureMatrix(const UVec4& viewport) const
  85. {
  86. const F32 atlasSize = F32(m_tileResolution * m_tileCountBothAxis);
  87. #if ANKI_COMPILER_GCC_COMPATIBLE
  88. # pragma GCC diagnostic push
  89. # pragma GCC diagnostic ignored "-Wpedantic" // Because GCC and clang throw an incorrect warning
  90. #endif
  91. const Vec2 uv(F32(viewport[0]) / atlasSize, F32(viewport[1]) / atlasSize);
  92. #if ANKI_COMPILER_GCC_COMPATIBLE
  93. # pragma GCC diagnostic pop
  94. #endif
  95. ANKI_ASSERT(uv >= Vec2(0.0f) && uv <= Vec2(1.0f));
  96. ANKI_ASSERT(viewport[2] == viewport[3]);
  97. const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
  98. const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
  99. return Mat4(sizeTextureSpace, 0.0f, 0.0f, uv.x, 0.0f, sizeTextureSpace, 0.0f, uv.y, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f) * biasMat4;
  100. }
  101. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  102. {
  103. ANKI_TRACE_SCOPED_EVENT(ShadowMapping);
  104. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  105. // Import
  106. if(m_rtImportedOnce) [[likely]]
  107. {
  108. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get());
  109. }
  110. else
  111. {
  112. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get(), TextureUsageBit::kSrvPixel);
  113. m_rtImportedOnce = true;
  114. }
  115. // First process the lights
  116. processLights(ctx);
  117. }
  118. void ShadowMapping::chooseDetail(const Vec3& cameraOrigin, const LightComponent& lightc, Vec2 lodDistances, U32& tileAllocatorHierarchy) const
  119. {
  120. if(lightc.getLightComponentType() == LightComponentType::kPoint)
  121. {
  122. const F32 distFromTheCamera = (cameraOrigin - lightc.getWorldPosition()).length() - lightc.getRadius();
  123. if(distFromTheCamera < lodDistances[0])
  124. {
  125. tileAllocatorHierarchy = kPointLightMaxTileAllocHierarchy;
  126. }
  127. else
  128. {
  129. tileAllocatorHierarchy = max(kPointLightMaxTileAllocHierarchy, 1u) - 1;
  130. }
  131. }
  132. else
  133. {
  134. ANKI_ASSERT(lightc.getLightComponentType() == LightComponentType::kSpot);
  135. // Get some data
  136. const Vec3 coneOrigin = lightc.getWorldPosition();
  137. const Vec3 coneDir = lightc.getDirection();
  138. const F32 coneAngle = lightc.getOuterAngle();
  139. // Compute the distance from the camera to the light cone
  140. const Vec3 V = cameraOrigin - coneOrigin;
  141. const F32 VlenSq = V.dot(V);
  142. const F32 V1len = V.dot(coneDir);
  143. const F32 distFromTheCamera = cos(coneAngle) * sqrt(VlenSq - V1len * V1len) - V1len * sin(coneAngle);
  144. if(distFromTheCamera < lodDistances[0])
  145. {
  146. tileAllocatorHierarchy = kSpotLightMaxTileAllocHierarchy;
  147. }
  148. else if(distFromTheCamera < lodDistances[1])
  149. {
  150. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 1u) - 1;
  151. }
  152. else
  153. {
  154. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 2u) - 2;
  155. }
  156. }
  157. }
  158. TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies,
  159. UVec4* atlasTileViewports)
  160. {
  161. ANKI_ASSERT(lightUuid > 0);
  162. ANKI_ASSERT(faceCount > 0);
  163. ANKI_ASSERT(hierarchies);
  164. TileAllocatorResult2 goodResult = TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached;
  165. for(U32 i = 0; i < faceCount; ++i)
  166. {
  167. TileAllocator::ArrayOfLightUuids kickedOutLights(&getRenderer().getFrameMemoryPool());
  168. Array<U32, 4> tileViewport;
  169. const TileAllocatorResult2 result = m_tileAlloc.allocate(
  170. GlobalFrameIndex::getSingleton().m_value, encodeTileHash(lightUuid, componentIndex, i), hierarchies[i], tileViewport, kickedOutLights);
  171. for(U64 kickedLightHash : kickedOutLights)
  172. {
  173. const LightHash hash = decodeTileHash(kickedLightHash);
  174. const Bool found = SceneGraph::getSingleton().getComponentArrays().getLights().indexExists(hash.m_unpacked.m_componentIndex);
  175. if(found)
  176. {
  177. LightComponent& lightc = SceneGraph::getSingleton().getComponentArrays().getLights()[hash.m_unpacked.m_componentIndex];
  178. if(lightc.getUuid() == hash.m_unpacked.m_uuid)
  179. {
  180. lightc.setShadowAtlasUvViewports({});
  181. }
  182. }
  183. }
  184. if(!!(result & TileAllocatorResult2::kAllocationFailed))
  185. {
  186. ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. Increase the %s or decrease the scene's shadow casters",
  187. g_cvarRenderSmTileCountPerRowOrColumn.getName().cstr());
  188. // Invalidate cache entries for what we already allocated
  189. for(U32 j = 0; j < i; ++j)
  190. {
  191. m_tileAlloc.invalidateCache(encodeTileHash(lightUuid, componentIndex, j));
  192. }
  193. return TileAllocatorResult2::kAllocationFailed;
  194. }
  195. if(!(result & TileAllocatorResult2::kTileCached))
  196. {
  197. g_svarTilesAllocated.increment(1);
  198. }
  199. goodResult &= result;
  200. // Set viewport
  201. const UVec4 viewport = UVec4(tileViewport) * m_tileResolution;
  202. atlasTileViewports[i] = viewport;
  203. }
  204. return goodResult;
  205. }
  206. void ShadowMapping::processLights(RenderingContext& ctx)
  207. {
  208. // First allocate tiles for the dir light and then build passes for points and spot lights. Then passes for the dir light. The dir light has many
  209. // passes and it will push the other types of lights further into the future. So do those first.
  210. // Vars
  211. const Vec3 cameraOrigin = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz;
  212. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  213. const CameraComponent& mainCam = SceneGraph::getSingleton().getActiveCameraNode().getFirstComponentOfType<CameraComponent>();
  214. // Allocate tiles for the dir light first but don't build any passes
  215. const LightComponent* dirLight = SceneGraph::getSingleton().getDirectionalLight();
  216. if(dirLight && (!dirLight->getShadowEnabled() || !g_cvarRenderShadowCascadeCount))
  217. {
  218. dirLight = nullptr; // Skip dir light
  219. }
  220. Array<UVec4, kMaxShadowCascades> dirLightAtlasViewports;
  221. if(dirLight)
  222. {
  223. const U32 cascadeCount = g_cvarRenderShadowCascadeCount;
  224. Array<U32, kMaxShadowCascades> hierarchies;
  225. for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
  226. {
  227. // Change the quality per cascade
  228. hierarchies[cascade] = kTileAllocHierarchyCount - 1 - chooseDirectionalLightShadowCascadeDetail(cascade);
  229. }
  230. [[maybe_unused]] const TileAllocatorResult2 res = allocateAtlasTiles(kMaxU32, 0, cascadeCount, &hierarchies[0], &dirLightAtlasViewports[0]);
  231. ANKI_ASSERT(!!(res & TileAllocatorResult2::kAllocationSucceded) && "Dir light should never fail");
  232. }
  233. // Process the point lights first
  234. WeakArray<LightComponent*> lights = getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_shadowLights;
  235. g_svarShadowLightsProcessed.increment(lights.getSize() + (dirLight != 0));
  236. for(LightComponent* lightc : lights)
  237. {
  238. if(lightc->getLightComponentType() != LightComponentType::kPoint || !lightc->getShadowEnabled())
  239. {
  240. continue;
  241. }
  242. // Prepare data to allocate tiles and allocate
  243. U32 hierarchy;
  244. chooseDetail(cameraOrigin, *lightc, {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance}, hierarchy);
  245. Array<U32, 6> hierarchies;
  246. hierarchies.fill(hierarchy);
  247. Array<UVec4, 6> atlasViewports;
  248. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 6, &hierarchies[0], &atlasViewports[0]);
  249. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  250. {
  251. // All good, update the light
  252. // Remove a few texels to avoid bilinear filtering bleeding
  253. F32 texelsBorder;
  254. if(g_cvarRenderSmPcf || g_cvarRenderSmPcss)
  255. {
  256. texelsBorder = 2.0f; // 2 texels
  257. }
  258. else
  259. {
  260. texelsBorder = 0.5f; // Half texel
  261. }
  262. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  263. F32 superTileSize = F32(atlasViewports[0][2]); // Should be the same for all tiles and faces
  264. superTileSize -= texelsBorder * 2.0f; // Remove from both sides
  265. Array<Vec4, 6> uvViewports;
  266. for(U face = 0; face < 6; ++face)
  267. {
  268. // Add a half texel to the viewport's start to avoid bilinear filtering bleeding
  269. const Vec2 uvViewportXY = (Vec2(atlasViewports[face].xy) + texelsBorder) / atlasResolution;
  270. uvViewports[face] = Vec4(uvViewportXY, Vec2(superTileSize / atlasResolution));
  271. }
  272. if(!(result & TileAllocatorResult2::kTileCached))
  273. {
  274. lightc->setShadowAtlasUvViewports(uvViewports);
  275. }
  276. // Vis testing
  277. const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
  278. DistanceGpuVisibilityInput visIn;
  279. visIn.m_passesName = generateTempPassName("Shadows point light light UUID:%u", lightc->getUuid());
  280. visIn.m_technique = RenderingTechnique::kDepth;
  281. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz;
  282. visIn.m_lodDistances = lodDistances;
  283. visIn.m_rgraph = &rgraph;
  284. visIn.m_pointOfTest = lightc->getWorldPosition();
  285. visIn.m_testRadius = lightc->getRadius();
  286. visIn.m_hashVisibles = true;
  287. GpuVisibilityOutput visOut;
  288. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  289. // Vet visibility
  290. const Bool renderAllways = !(result & TileAllocatorResult2::kTileCached);
  291. BufferView clearTileIndirectArgs;
  292. if(!renderAllways)
  293. {
  294. clearTileIndirectArgs = createVetVisibilityPass(generateTempPassName("Shadows: Vet point light light UUID:%u", lightc->getUuid()),
  295. *lightc, visOut, rgraph);
  296. }
  297. // Draw
  298. Array<ShadowSubpassInfo, 6> subpasses;
  299. for(U32 face = 0; face < 6; ++face)
  300. {
  301. Frustum frustum;
  302. frustum.init(FrustumType::kPerspective);
  303. frustum.setPerspective(kClusterObjectFrustumNearPlane, lightc->getRadius(), kPi / 2.0f, kPi / 2.0f);
  304. frustum.setWorldTransform(
  305. Transform(lightc->getWorldPosition().xyz0, Frustum::getOmnidirectionalFrustumRotations()[face], Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
  306. frustum.update();
  307. subpasses[face].m_clearTileIndirectArgs = clearTileIndirectArgs;
  308. subpasses[face].m_viewMat = frustum.getViewMatrix();
  309. subpasses[face].m_viewport = atlasViewports[face];
  310. subpasses[face].m_viewProjMat = frustum.getViewProjectionMatrix();
  311. }
  312. createDrawShadowsPass(subpasses, visOut, generateTempPassName("Shadows: Point light UUID:%u", lightc->getUuid()), rgraph);
  313. }
  314. else
  315. {
  316. // Can't be a caster from now on
  317. lightc->setShadowAtlasUvViewports({});
  318. }
  319. }
  320. // Process the spot lights 2nd
  321. for(LightComponent* lightc : lights)
  322. {
  323. if(lightc->getLightComponentType() != LightComponentType::kSpot || !lightc->getShadowEnabled())
  324. {
  325. continue;
  326. }
  327. // Allocate tile
  328. U32 hierarchy;
  329. chooseDetail(cameraOrigin, *lightc, {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance}, hierarchy);
  330. UVec4 atlasViewport;
  331. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport);
  332. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  333. {
  334. // All good, update the light
  335. if(!(result & TileAllocatorResult2::kTileCached))
  336. {
  337. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  338. const Vec4 uvViewport = Vec4(atlasViewport) / atlasResolution;
  339. lightc->setShadowAtlasUvViewports({&uvViewport, 1});
  340. }
  341. // Vis testing
  342. const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
  343. FrustumGpuVisibilityInput visIn;
  344. visIn.m_passesName = generateTempPassName("Shadows spot light UUID:%u", lightc->getUuid());
  345. visIn.m_technique = RenderingTechnique::kDepth;
  346. visIn.m_lodReferencePoint = cameraOrigin;
  347. visIn.m_lodDistances = lodDistances;
  348. visIn.m_rgraph = &rgraph;
  349. visIn.m_viewProjectionMatrix = lightc->getSpotLightViewProjectionMatrix();
  350. visIn.m_hashVisibles = true;
  351. visIn.m_viewportSize = atlasViewport.zw;
  352. GpuVisibilityOutput visOut;
  353. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  354. // Vet visibility
  355. const Bool renderAllways = !(result & TileAllocatorResult2::kTileCached);
  356. BufferView clearTileIndirectArgs;
  357. if(!renderAllways)
  358. {
  359. clearTileIndirectArgs =
  360. createVetVisibilityPass(generateTempPassName("Shadows: Vet spot light UUID:%u", lightc->getUuid()), *lightc, visOut, rgraph);
  361. }
  362. // Add draw pass
  363. createDrawShadowsPass(atlasViewport, lightc->getSpotLightViewProjectionMatrix(), lightc->getSpotLightViewMatrix(), visOut,
  364. clearTileIndirectArgs, {}, generateTempPassName("Shadows: Spot light UUID:%u", lightc->getUuid()), rgraph);
  365. }
  366. else
  367. {
  368. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  369. lightc->setShadowAtlasUvViewports({});
  370. }
  371. }
  372. // Process the directional light last
  373. if(dirLight)
  374. {
  375. const U32 cascadeCount = g_cvarRenderShadowCascadeCount;
  376. // Compute the view projection matrices
  377. Array<F32, kMaxShadowCascades> cascadeDistances;
  378. static_assert(kMaxShadowCascades == 4);
  379. cascadeDistances[0] = g_cvarRenderShadowCascade0Distance;
  380. cascadeDistances[1] = g_cvarRenderShadowCascade1Distance;
  381. cascadeDistances[2] = g_cvarRenderShadowCascade2Distance;
  382. cascadeDistances[3] = g_cvarRenderShadowCascade3Distance;
  383. Array<Mat4, kMaxShadowCascades> cascadeViewProjMats;
  384. Array<Mat3x4, kMaxShadowCascades> cascadeViewMats;
  385. Array<Mat4, kMaxShadowCascades> cascadeProjMats;
  386. Array<Array<F32, U32(FrustumPlaneType::kCount)>, kMaxShadowCascades> cascadePlanes;
  387. dirLight->computeCascadeFrustums(mainCam.getFrustum(), {&cascadeDistances[0], cascadeCount}, {&cascadeProjMats[0], cascadeCount},
  388. {&cascadeViewMats[0], cascadeCount}, {cascadePlanes.getBegin(), cascadeCount});
  389. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  390. {
  391. cascadeViewProjMats[cascade] = cascadeProjMats[cascade] * Mat4(cascadeViewMats[cascade], Vec4(0.0f, 0.0f, 0.0f, 1.0f));
  392. }
  393. // HZB generation
  394. HzbDirectionalLightInput hzbGenIn;
  395. hzbGenIn.m_cascadeCount = cascadeCount;
  396. hzbGenIn.m_depthBufferRt = getGBuffer().getDepthRt();
  397. hzbGenIn.m_depthBufferRtSize = getRenderer().getInternalResolution();
  398. hzbGenIn.m_cameraProjectionMatrix = ctx.m_matrices.m_projection;
  399. hzbGenIn.m_cameraInverseViewProjectionMatrix = ctx.m_matrices.m_invertedViewProjection;
  400. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  401. {
  402. hzbGenIn.m_cascades[cascade].m_hzbRt = rgraph.newRenderTarget(m_cascadeHzbRtDescrs[cascade]);
  403. hzbGenIn.m_cascades[cascade].m_hzbRtSize = UVec2(m_cascadeHzbRtDescrs[cascade].m_width, m_cascadeHzbRtDescrs[cascade].m_height);
  404. hzbGenIn.m_cascades[cascade].m_viewMatrix = cascadeViewMats[cascade];
  405. hzbGenIn.m_cascades[cascade].m_projectionMatrix = cascadeProjMats[cascade];
  406. hzbGenIn.m_cascades[cascade].m_cascadeMaxDistance = cascadeDistances[cascade];
  407. }
  408. getRenderer().getHzbGenerator().populateRenderGraphDirectionalLight(hzbGenIn, rgraph);
  409. // Create passes per cascade
  410. for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
  411. {
  412. // Vis testing
  413. const Array<F32, kMaxLodCount - 1> lodDistances = {g_cvarRenderLod0MaxDistance, g_cvarRenderLod1MaxDistance};
  414. FrustumGpuVisibilityInput visIn;
  415. visIn.m_passesName = generateTempPassName("Shadows: Dir light cascade cascade:%u", cascade);
  416. visIn.m_technique = RenderingTechnique::kDepth;
  417. visIn.m_viewProjectionMatrix = cascadeViewProjMats[cascade];
  418. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz;
  419. visIn.m_lodDistances = lodDistances;
  420. visIn.m_hzbRt = &hzbGenIn.m_cascades[cascade].m_hzbRt;
  421. visIn.m_rgraph = &rgraph;
  422. visIn.m_viewportSize = dirLightAtlasViewports[cascade].zw;
  423. GpuVisibilityOutput visOut;
  424. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  425. // Draw
  426. createDrawShadowsPass(dirLightAtlasViewports[cascade], cascadeViewProjMats[cascade], cascadeViewMats[cascade], visOut, {},
  427. hzbGenIn.m_cascades[cascade].m_hzbRt, generateTempPassName("Shadows: Dir light cascade:%u", cascade), rgraph);
  428. // Update the texture matrix to point to the correct region in the atlas
  429. ctx.m_dirLightTextureMatrices[cascade] = createSpotLightTextureMatrix(dirLightAtlasViewports[cascade]) * cascadeViewProjMats[cascade];
  430. ctx.m_dirLightFarPlanes[cascade] = cascadePlanes[cascade][FrustumPlaneType::kFar];
  431. const F32 texelSize = 1.0f / F32(m_atlasTex->getWidth());
  432. if(cascade == 0)
  433. {
  434. ctx.m_dirLightPcfTexelRadius[cascade] = kPcfTexelRadius * texelSize;
  435. }
  436. else
  437. {
  438. // Make the PCF radius proportional to the 1st cascade to make PCF blurring for all cascades look somewhat similar
  439. const F32 cascade0Meters = cascadePlanes[0][FrustumPlaneType::kRight] - cascadePlanes[0][FrustumPlaneType::kLeft];
  440. const F32 cascadeXMeters = cascadePlanes[cascade][FrustumPlaneType::kRight] - cascadePlanes[cascade][FrustumPlaneType::kLeft];
  441. ctx.m_dirLightPcfTexelRadius[cascade] = ctx.m_dirLightPcfTexelRadius[0] * cascade0Meters / cascadeXMeters;
  442. if(ctx.m_dirLightPcfTexelRadius[cascade] < texelSize * 0.5)
  443. {
  444. // Too small, don't bother
  445. ctx.m_dirLightPcfTexelRadius[cascade] = 0.0f;
  446. }
  447. }
  448. }
  449. }
  450. }
  451. BufferView ShadowMapping::createVetVisibilityPass(CString passName, const LightComponent& lightc, const GpuVisibilityOutput& visOut,
  452. RenderGraphBuilder& rgraph) const
  453. {
  454. BufferView clearTileIndirectArgs;
  455. clearTileIndirectArgs = GpuVisibleTransientMemoryPool::getSingleton().allocateStructuredBuffer<DrawIndirectArgs>(1);
  456. NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass(passName);
  457. if(visOut.containsDrawcalls())
  458. {
  459. // The shader doesn't actually write to the handle but have it as a write dependency for the drawer to correctly wait for this pass
  460. pass.newBufferDependency(visOut.m_dependency, BufferUsageBit::kUavCompute);
  461. }
  462. pass.setWork([this, &lightc, clearTileIndirectArgs, visOut](RenderPassWorkContext& rpass) {
  463. ANKI_TRACE_SCOPED_EVENT(ShadowmappingVet);
  464. if(!visOut.containsDrawcalls()) [[unlikely]]
  465. {
  466. return;
  467. }
  468. CommandBuffer& cmdb = *rpass.m_commandBuffer;
  469. cmdb.bindShaderProgram(m_vetVisibilityGrProg.get());
  470. const UVec4 lightIndex(lightc.getGpuSceneLightAllocation().getIndex());
  471. cmdb.setFastConstants(&lightIndex, sizeof(lightIndex));
  472. cmdb.bindSrv(0, 0, visOut.m_visiblesHashBuffer);
  473. cmdb.bindUav(0, 0,
  474. visOut.m_legacy.m_mdiDrawCountsBuffer.isValid() ? visOut.m_legacy.m_mdiDrawCountsBuffer
  475. : BufferView(getDummyGpuResources().m_buffer.get()).setRange(sizeof(U32)));
  476. cmdb.bindUav(1, 0, GpuSceneArrays::Light::getSingleton().getBufferView());
  477. cmdb.bindUav(2, 0, GpuSceneArrays::LightVisibleRenderablesHash::getSingleton().getBufferView());
  478. cmdb.bindUav(3, 0, clearTileIndirectArgs);
  479. cmdb.bindUav(4, 0,
  480. visOut.m_mesh.m_dispatchMeshIndirectArgsBuffer.isValid()
  481. ? visOut.m_mesh.m_dispatchMeshIndirectArgsBuffer
  482. : BufferView(getDummyGpuResources().m_buffer.get()).setRange(sizeof(DispatchIndirectArgs)));
  483. cmdb.bindUav(5, 0,
  484. visOut.m_mesh.m_drawIndirectArgs.isValid()
  485. ? visOut.m_mesh.m_drawIndirectArgs
  486. : BufferView(getDummyGpuResources().m_buffer.get()).setRange(sizeof(DrawIndirectArgs)));
  487. ANKI_ASSERT(RenderStateBucketContainer::getSingleton().getBucketCount(RenderingTechnique::kDepth) <= 64 && "TODO");
  488. cmdb.dispatchCompute(1, 1, 1);
  489. });
  490. return clearTileIndirectArgs;
  491. }
  492. void ShadowMapping::createDrawShadowsPass(const UVec4& viewport, const Mat4& viewProjMat, const Mat3x4& viewMat, const GpuVisibilityOutput& visOut,
  493. const BufferView& clearTileIndirectArgs, const RenderTargetHandle hzbRt, CString passName,
  494. RenderGraphBuilder& rgraph)
  495. {
  496. ShadowSubpassInfo spass;
  497. spass.m_clearTileIndirectArgs = clearTileIndirectArgs;
  498. spass.m_hzbRt = hzbRt;
  499. spass.m_viewMat = viewMat;
  500. spass.m_viewport = viewport;
  501. spass.m_viewProjMat = viewProjMat;
  502. createDrawShadowsPass({&spass, 1}, visOut, passName, rgraph);
  503. }
  504. void ShadowMapping::createDrawShadowsPass(ConstWeakArray<ShadowSubpassInfo> subpasses_, const GpuVisibilityOutput& visOut, CString passName,
  505. RenderGraphBuilder& rgraph)
  506. {
  507. WeakArray<ShadowSubpassInfo> subpasses;
  508. newArray<ShadowSubpassInfo>(getRenderer().getFrameMemoryPool(), subpasses_.getSize(), subpasses);
  509. memcpy(subpasses.getBegin(), subpasses_.getBegin(), subpasses.getSizeInBytes());
  510. // Create the pass
  511. GraphicsRenderPass& pass = rgraph.newGraphicsRenderPass(passName);
  512. GraphicsRenderPassTargetDesc smRti(m_runCtx.m_rt);
  513. smRti.m_loadOperation = RenderTargetLoadOperation::kLoad;
  514. smRti.m_clearValue.m_depthStencil.m_depth = 1.0f;
  515. smRti.m_subresource.m_depthStencilAspect = DepthStencilAspectBit::kDepth;
  516. pass.setRenderpassInfo({}, &smRti);
  517. if(visOut.containsDrawcalls())
  518. {
  519. pass.newBufferDependency(visOut.m_dependency, BufferUsageBit::kIndirectDraw);
  520. }
  521. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kRtvDsvWrite);
  522. pass.setWork([this, visOut, subpasses](RenderPassWorkContext& rgraphCtx) {
  523. ANKI_TRACE_SCOPED_EVENT(ShadowMapping);
  524. if(!visOut.containsDrawcalls()) [[unlikely]]
  525. {
  526. return;
  527. }
  528. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  529. for(U32 i = 0; i < subpasses.getSize(); ++i)
  530. {
  531. const ShadowSubpassInfo& spass = subpasses[i];
  532. cmdb.setViewport(spass.m_viewport[0], spass.m_viewport[1], spass.m_viewport[2], spass.m_viewport[3]);
  533. // Clear the tile
  534. {
  535. cmdb.bindShaderProgram(m_clearDepthGrProg.get());
  536. cmdb.setDepthCompareOperation(CompareOperation::kAlways);
  537. if(spass.m_clearTileIndirectArgs.isValid())
  538. {
  539. cmdb.drawIndirect(PrimitiveTopology::kTriangles, spass.m_clearTileIndirectArgs);
  540. }
  541. else
  542. {
  543. cmdb.draw(PrimitiveTopology::kTriangles, 3);
  544. }
  545. cmdb.setDepthCompareOperation(CompareOperation::kLess);
  546. }
  547. // Set state
  548. cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  549. RenderableDrawerArguments args;
  550. args.m_renderingTechinuqe = RenderingTechnique::kDepth;
  551. args.m_viewMatrix = spass.m_viewMat;
  552. args.m_cameraTransform = spass.m_viewMat.invertTransformation();
  553. args.m_viewProjectionMatrix = spass.m_viewProjMat;
  554. args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
  555. args.m_sampler = getRenderer().getSamplers().m_trilinearRepeat.get();
  556. args.m_viewport = UVec4(spass.m_viewport[0], spass.m_viewport[1], spass.m_viewport[2], spass.m_viewport[3]);
  557. args.fill(visOut);
  558. getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
  559. cmdb.setPolygonOffset(0.0, 0.0);
  560. }
  561. });
  562. }
  563. } // end namespace anki