ShadowMapping.cpp 27 KB

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