ShadowMapping.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. // Copyright (C) 2009-2023, 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/Core/App.h>
  10. #include <AnKi/Core/StatsSet.h>
  11. #include <AnKi/Util/ThreadHive.h>
  12. #include <AnKi/Util/Tracer.h>
  13. #include <AnKi/Scene/Components/LightComponent.h>
  14. #include <AnKi/Scene/Components/CameraComponent.h>
  15. namespace anki {
  16. static NumericCVar<U32> g_shadowMappingTileResolutionCVar(CVarSubsystem::kRenderer, "ShadowMappingTileResolution", (ANKI_PLATFORM_MOBILE) ? 128 : 256,
  17. 16, 2048, "Shadowmapping tile resolution");
  18. static NumericCVar<U32> g_shadowMappingTileCountPerRowOrColumnCVar(CVarSubsystem::kRenderer, "ShadowMappingTileCountPerRowOrColumn", 32, 1, 256,
  19. "Shadowmapping atlas will have this number squared number of tiles");
  20. NumericCVar<U32> g_shadowMappingPcfCVar(CVarSubsystem::kRenderer, "ShadowMappingPcf", (ANKI_PLATFORM_MOBILE) ? 0 : 1, 0, 1,
  21. "Shadow PCF (CVarSubsystem::kRenderer, 0: off, 1: on)");
  22. static StatCounter g_tilesAllocatedStatVar(StatCategory::kRenderer, "Shadow tiles (re)allocated");
  23. class LightHash
  24. {
  25. public:
  26. union
  27. {
  28. class
  29. {
  30. public:
  31. U64 m_uuid : 31;
  32. U64 m_componentIndex : 30;
  33. U64 m_faceIdx : 3;
  34. } 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. class ShadowMapping::ViewportWorkItem
  54. {
  55. public:
  56. UVec4 m_viewport;
  57. Mat4 m_viewProjMat;
  58. Mat3x4 m_viewMat;
  59. GpuVisibilityOutput m_visOut;
  60. };
  61. Error ShadowMapping::init()
  62. {
  63. const Error err = initInternal();
  64. if(err)
  65. {
  66. ANKI_R_LOGE("Failed to initialize shadowmapping");
  67. }
  68. return err;
  69. }
  70. Error ShadowMapping::initInternal()
  71. {
  72. // Init RT
  73. {
  74. m_tileResolution = g_shadowMappingTileResolutionCVar.get();
  75. m_tileCountBothAxis = g_shadowMappingTileCountPerRowOrColumnCVar.get();
  76. ANKI_R_LOGV("Initializing shadowmapping. Atlas resolution %ux%u", m_tileResolution * m_tileCountBothAxis,
  77. m_tileResolution * m_tileCountBothAxis);
  78. // RT
  79. const TextureUsageBit usage = TextureUsageBit::kSampledFragment | TextureUsageBit::kSampledCompute | TextureUsageBit::kAllFramebuffer;
  80. TextureInitInfo texinit = getRenderer().create2DRenderTargetInitInfo(
  81. m_tileResolution * m_tileCountBothAxis, m_tileResolution * m_tileCountBothAxis, Format::kD16_Unorm, usage, "ShadowAtlas");
  82. ClearValue clearVal;
  83. clearVal.m_colorf[0] = 1.0f;
  84. m_atlasTex = getRenderer().createAndClearRenderTarget(texinit, TextureUsageBit::kSampledFragment, clearVal);
  85. }
  86. // Tiles
  87. m_tileAlloc.init(m_tileCountBothAxis, m_tileCountBothAxis, kTileAllocHierarchyCount, true);
  88. m_fbDescr.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::kDepth;
  89. m_fbDescr.m_depthStencilAttachment.m_loadOperation = AttachmentLoadOperation::kLoad;
  90. m_fbDescr.bake();
  91. ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/ShadowmappingClearDepth.ankiprogbin", m_clearDepthProg));
  92. const ShaderProgramResourceVariant* variant;
  93. m_clearDepthProg->getOrCreateVariant(variant);
  94. m_clearDepthGrProg.reset(&variant->getProgram());
  95. for(U32 i = 0; i < kMaxShadowCascades; ++i)
  96. {
  97. RendererString name;
  98. name.sprintf("DirLight HZB #%d", i);
  99. const U32 cascadeResolution = (m_tileResolution * (1 << (kTileAllocHierarchyCount - 1))) >> chooseDirectionalLightShadowCascadeDetail(i);
  100. UVec2 size(min(cascadeResolution, 1024u));
  101. size /= 2;
  102. m_cascadeHzbRtDescrs[i] = getRenderer().create2DRenderTargetDescription(size.x(), size.y(), Format::kR8_Unorm, name);
  103. m_cascadeHzbRtDescrs[i].m_mipmapCount = U8(computeMaxMipmapCount2d(m_cascadeHzbRtDescrs[i].m_width, m_cascadeHzbRtDescrs[i].m_height));
  104. m_cascadeHzbRtDescrs[i].bake();
  105. }
  106. return Error::kNone;
  107. }
  108. Mat4 ShadowMapping::createSpotLightTextureMatrix(const UVec4& viewport) const
  109. {
  110. const F32 atlasSize = F32(m_tileResolution * m_tileCountBothAxis);
  111. #if ANKI_COMPILER_GCC_COMPATIBLE
  112. # pragma GCC diagnostic push
  113. # pragma GCC diagnostic ignored "-Wpedantic" // Because GCC and clang throw an incorrect warning
  114. #endif
  115. const Vec2 uv(F32(viewport[0]) / atlasSize, F32(viewport[1]) / atlasSize);
  116. #if ANKI_COMPILER_GCC_COMPATIBLE
  117. # pragma GCC diagnostic pop
  118. #endif
  119. ANKI_ASSERT(uv >= Vec2(0.0f) && uv <= Vec2(1.0f));
  120. ANKI_ASSERT(viewport[2] == viewport[3]);
  121. const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
  122. 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);
  123. 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)
  124. * biasMat4;
  125. }
  126. void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
  127. {
  128. ANKI_TRACE_SCOPED_EVENT(RSm);
  129. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  130. // Import
  131. if(m_rtImportedOnce) [[likely]]
  132. {
  133. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get());
  134. }
  135. else
  136. {
  137. m_runCtx.m_rt = rgraph.importRenderTarget(m_atlasTex.get(), TextureUsageBit::kSampledFragment);
  138. m_rtImportedOnce = true;
  139. }
  140. // First process the lights
  141. processLights(ctx);
  142. // Build the render graph
  143. if(m_runCtx.m_workItems.getSize())
  144. {
  145. // Will have to create render passes
  146. // Compute render area
  147. const U32 minx = m_runCtx.m_renderAreaMin.x();
  148. const U32 miny = m_runCtx.m_renderAreaMin.y();
  149. const U32 width = m_runCtx.m_renderAreaMax.x() - m_runCtx.m_renderAreaMin.x();
  150. const U32 height = m_runCtx.m_renderAreaMax.y() - m_runCtx.m_renderAreaMin.y();
  151. GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Shadowmapping");
  152. for(const ViewportWorkItem& work : m_runCtx.m_workItems)
  153. {
  154. pass.newBufferDependency(work.m_visOut.m_mdiDrawCountsHandle, BufferUsageBit::kIndirectDraw);
  155. }
  156. TextureSubresourceInfo subresource = TextureSubresourceInfo(DepthStencilAspectBit::kDepth);
  157. pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kAllFramebuffer, subresource);
  158. pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(),
  159. BufferUsageBit::kStorageGeometryRead | BufferUsageBit::kStorageFragmentRead);
  160. pass.setFramebufferInfo(m_fbDescr, {}, m_runCtx.m_rt, {}, minx, miny, width, height);
  161. pass.setWork(1, [this](RenderPassWorkContext& rgraphCtx) {
  162. runShadowMapping(rgraphCtx);
  163. });
  164. }
  165. }
  166. void ShadowMapping::chooseDetail(const Vec3& cameraOrigin, const LightComponent& lightc, U32& tileAllocatorHierarchy) const
  167. {
  168. if(lightc.getLightComponentType() == LightComponentType::kPoint)
  169. {
  170. const F32 distFromTheCamera = (cameraOrigin - lightc.getWorldPosition()).getLength() - lightc.getRadius();
  171. if(distFromTheCamera < g_lod0MaxDistanceCVar.get())
  172. {
  173. tileAllocatorHierarchy = kPointLightMaxTileAllocHierarchy;
  174. }
  175. else
  176. {
  177. tileAllocatorHierarchy = max(kPointLightMaxTileAllocHierarchy, 1u) - 1;
  178. }
  179. }
  180. else
  181. {
  182. ANKI_ASSERT(lightc.getLightComponentType() == LightComponentType::kSpot);
  183. // Get some data
  184. const Vec3 coneOrigin = lightc.getWorldPosition();
  185. const Vec3 coneDir = lightc.getDirection();
  186. const F32 coneAngle = lightc.getOuterAngle();
  187. // Compute the distance from the camera to the light cone
  188. const Vec3 V = cameraOrigin - coneOrigin;
  189. const F32 VlenSq = V.dot(V);
  190. const F32 V1len = V.dot(coneDir);
  191. const F32 distFromTheCamera = cos(coneAngle) * sqrt(VlenSq - V1len * V1len) - V1len * sin(coneAngle);
  192. if(distFromTheCamera < g_lod0MaxDistanceCVar.get())
  193. {
  194. tileAllocatorHierarchy = kSpotLightMaxTileAllocHierarchy;
  195. }
  196. else if(distFromTheCamera < g_lod1MaxDistanceCVar.get())
  197. {
  198. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 1u) - 1;
  199. }
  200. else
  201. {
  202. tileAllocatorHierarchy = max(kSpotLightMaxTileAllocHierarchy, 2u) - 2;
  203. }
  204. }
  205. }
  206. TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies,
  207. UVec4* atlasTileViewports)
  208. {
  209. ANKI_ASSERT(lightUuid > 0);
  210. ANKI_ASSERT(faceCount > 0);
  211. ANKI_ASSERT(hierarchies);
  212. TileAllocatorResult2 goodResult = TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached;
  213. for(U i = 0; i < faceCount; ++i)
  214. {
  215. TileAllocator2::ArrayOfLightUuids kickedOutLights(&getRenderer().getFrameMemoryPool());
  216. Array<U32, 4> tileViewport;
  217. const TileAllocatorResult2 result = m_tileAlloc.allocate(
  218. GlobalFrameIndex::getSingleton().m_value, encodeTileHash(lightUuid, componentIndex, i), hierarchies[i], tileViewport, kickedOutLights);
  219. for(U64 kickedLightHash : kickedOutLights)
  220. {
  221. const LightHash hash = decodeTileHash(kickedLightHash);
  222. const Bool found = SceneGraph::getSingleton().getComponentArrays().getLights().indexExists(hash.m_unpacked.m_componentIndex);
  223. if(found)
  224. {
  225. LightComponent& lightc = SceneGraph::getSingleton().getComponentArrays().getLights()[hash.m_unpacked.m_componentIndex];
  226. if(lightc.getUuid() == hash.m_unpacked.m_uuid)
  227. {
  228. lightc.setShadowAtlasUvViewports({});
  229. }
  230. }
  231. }
  232. if(!!(result & TileAllocatorResult2::kAllocationFailed))
  233. {
  234. 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",
  235. g_shadowMappingTileCountPerRowOrColumnCVar.getFullName().cstr());
  236. // Invalidate cache entries for what we already allocated
  237. for(U j = 0; j < i; ++j)
  238. {
  239. m_tileAlloc.invalidateCache(encodeTileHash(lightUuid, componentIndex, j));
  240. }
  241. return TileAllocatorResult2::kAllocationFailed;
  242. }
  243. if(!(result & TileAllocatorResult2::kTileCached))
  244. {
  245. g_tilesAllocatedStatVar.increment(1);
  246. }
  247. goodResult &= result;
  248. // Set viewport
  249. const UVec4 viewport = UVec4(tileViewport) * m_tileResolution;
  250. atlasTileViewports[i] = viewport;
  251. m_runCtx.m_renderAreaMin = m_runCtx.m_renderAreaMin.min(UVec2(viewport[0], viewport[1]));
  252. m_runCtx.m_renderAreaMax = m_runCtx.m_renderAreaMax.max(UVec2(viewport[0] + viewport[2], viewport[1] + viewport[3]));
  253. }
  254. return goodResult;
  255. }
  256. void ShadowMapping::processLights(RenderingContext& ctx)
  257. {
  258. m_runCtx.m_renderAreaMin = UVec2(kMaxU32, kMaxU32);
  259. m_runCtx.m_renderAreaMax = UVec2(kMinU32, kMinU32);
  260. // Vars
  261. const Vec3 cameraOrigin = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  262. DynamicArray<ViewportWorkItem, MemoryPoolPtrWrapper<StackMemoryPool>> workItems(ctx.m_tempPool);
  263. RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
  264. const CameraComponent& mainCam = SceneGraph::getSingleton().getActiveCameraNode().getFirstComponentOfType<CameraComponent>();
  265. // Process the directional light first.
  266. const LightComponent* dirLight = SceneGraph::getSingleton().getDirectionalLight();
  267. if(dirLight && dirLight->getShadowEnabled() && mainCam.getShadowCascadeCount())
  268. {
  269. const U32 cascadeCount = mainCam.getShadowCascadeCount();
  270. Array<U32, kMaxShadowCascades> cascadeIndices;
  271. Array<U32, kMaxShadowCascades> hierarchies;
  272. for(U32 cascade = 0; cascade < cascadeCount; ++cascade)
  273. {
  274. cascadeIndices[cascade] = cascade;
  275. // Change the quality per cascade
  276. hierarchies[cascade] = kTileAllocHierarchyCount - 1 - chooseDirectionalLightShadowCascadeDetail(cascade);
  277. }
  278. Array<UVec4, kMaxShadowCascades> atlasViewports;
  279. [[maybe_unused]] const TileAllocatorResult2 res = allocateAtlasTiles(kMaxU32, 0, cascadeCount, &hierarchies[0], &atlasViewports[0]);
  280. ANKI_ASSERT(!!(res & TileAllocatorResult2::kAllocationSucceded) && "Dir light should never fail");
  281. // Compute the view projection matrices
  282. Array<F32, kMaxShadowCascades> cascadeDistances;
  283. for(U32 i = 0; i < cascadeCount; ++i)
  284. {
  285. cascadeDistances[i] = mainCam.getShadowCascadeDistance(i);
  286. }
  287. Array<Mat4, kMaxShadowCascades> cascadeViewProjMats;
  288. Array<Mat3x4, kMaxShadowCascades> cascadeViewMats;
  289. dirLight->computeCascadeFrustums(mainCam.getFrustum(), {&cascadeDistances[0], cascadeCount}, {&cascadeViewProjMats[0], cascadeCount},
  290. {&cascadeViewMats[0], cascadeCount});
  291. // HZB generation
  292. Array<RenderTargetHandle, kMaxShadowCascades> hzbRts;
  293. Array<UVec2, kMaxShadowCascades> hzbSizes;
  294. Array<Mat4, kMaxShadowCascades> dstViewProjectionMats;
  295. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  296. {
  297. hzbRts[cascade] = rgraph.newRenderTarget(m_cascadeHzbRtDescrs[cascade]);
  298. hzbSizes[cascade] = UVec2(m_cascadeHzbRtDescrs[cascade].m_width, m_cascadeHzbRtDescrs[cascade].m_height);
  299. dstViewProjectionMats[cascade] = cascadeViewProjMats[cascade];
  300. }
  301. getRenderer().getHzbGenerator().populateRenderGraphDirectionalLight(
  302. getRenderer().getGBuffer().getDepthRt(), getRenderer().getInternalResolution(), {hzbRts.getBegin(), cascadeCount},
  303. {dstViewProjectionMats.getBegin(), cascadeCount}, {hzbSizes.getBegin(), cascadeCount}, ctx.m_matrices.m_invertedViewProjection, rgraph);
  304. // Vis testing
  305. for(U cascade = 0; cascade < cascadeCount; ++cascade)
  306. {
  307. ViewportWorkItem& work = *workItems.emplaceBack();
  308. work.m_viewProjMat = cascadeViewProjMats[cascade];
  309. work.m_viewMat = cascadeViewMats[cascade];
  310. work.m_viewport = atlasViewports[cascade];
  311. // Vis testing
  312. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  313. FrustumGpuVisibilityInput visIn;
  314. visIn.m_passesName = "Shadows visibility: Dir light";
  315. visIn.m_technique = RenderingTechnique::kDepth;
  316. visIn.m_viewProjectionMatrix = cascadeViewProjMats[cascade];
  317. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  318. visIn.m_lodDistances = lodDistances;
  319. visIn.m_hzbRt = &hzbRts[cascade];
  320. visIn.m_rgraph = &rgraph;
  321. getRenderer().getGpuVisibility().populateRenderGraph(visIn, work.m_visOut);
  322. // Update the texture matrix to point to the correct region in the atlas
  323. ctx.m_dirLightTextureMatrices[cascade] = createSpotLightTextureMatrix(atlasViewports[cascade]) * cascadeViewProjMats[cascade];
  324. }
  325. }
  326. // Process the point lights.
  327. WeakArray<LightComponent*> lights = getRenderer().getPrimaryNonRenderableVisibility().getInterestingVisibleComponents().m_shadowLights;
  328. for(LightComponent* lightc : lights)
  329. {
  330. if(lightc->getLightComponentType() != LightComponentType::kPoint || !lightc->getShadowEnabled())
  331. {
  332. continue;
  333. }
  334. // Prepare data to allocate tiles and allocate
  335. U32 hierarchy;
  336. chooseDetail(cameraOrigin, *lightc, hierarchy);
  337. Array<U32, 6> hierarchies;
  338. hierarchies.fill(hierarchy);
  339. Array<UVec4, 6> atlasViewports;
  340. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 6, &hierarchies[0], &atlasViewports[0]);
  341. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  342. {
  343. // All good, update the light
  344. // Remove a few texels to avoid bilinear filtering bleeding
  345. F32 texelsBorder;
  346. if(g_shadowMappingPcfCVar.get())
  347. {
  348. texelsBorder = 2.0f; // 2 texels
  349. }
  350. else
  351. {
  352. texelsBorder = 0.5f; // Half texel
  353. }
  354. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  355. F32 superTileSize = F32(atlasViewports[0][2]); // Should be the same for all tiles and faces
  356. superTileSize -= texelsBorder * 2.0f; // Remove from both sides
  357. Array<Vec4, 6> uvViewports;
  358. for(U face = 0; face < 6; ++face)
  359. {
  360. // Add a half texel to the viewport's start to avoid bilinear filtering bleeding
  361. const Vec2 uvViewportXY = (Vec2(atlasViewports[face].xy()) + texelsBorder) / atlasResolution;
  362. uvViewports[face] = Vec4(uvViewportXY, Vec2(superTileSize / atlasResolution));
  363. }
  364. if(!(result & TileAllocatorResult2::kTileCached))
  365. {
  366. lightc->setShadowAtlasUvViewports(uvViewports);
  367. }
  368. // Vis testing
  369. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  370. DistanceGpuVisibilityInput visIn;
  371. visIn.m_passesName = "Shadows visibility: Point light";
  372. visIn.m_technique = RenderingTechnique::kDepth;
  373. visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
  374. visIn.m_lodDistances = lodDistances;
  375. visIn.m_rgraph = &rgraph;
  376. visIn.m_pointOfTest = lightc->getWorldPosition();
  377. visIn.m_testRadius = lightc->getRadius();
  378. GpuVisibilityOutput visOut;
  379. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  380. // Add work
  381. for(U32 face = 0; face < 6; ++face)
  382. {
  383. Frustum frustum;
  384. frustum.init(FrustumType::kPerspective);
  385. frustum.setPerspective(kClusterObjectFrustumNearPlane, lightc->getRadius(), kPi / 2.0f, kPi / 2.0f);
  386. frustum.setWorldTransform(Transform(lightc->getWorldPosition().xyz0(), Frustum::getOmnidirectionalFrustumRotations()[face], 1.0f));
  387. frustum.update();
  388. ViewportWorkItem& work = *workItems.emplaceBack();
  389. work.m_viewProjMat = frustum.getViewProjectionMatrix();
  390. work.m_viewMat = frustum.getViewMatrix();
  391. work.m_viewport = atlasViewports[face];
  392. work.m_visOut = visOut;
  393. }
  394. }
  395. else
  396. {
  397. // Can't be a caster from now on
  398. lightc->setShadowAtlasUvViewports({});
  399. }
  400. }
  401. // Process the spot lights
  402. for(LightComponent* lightc : lights)
  403. {
  404. if(lightc->getLightComponentType() != LightComponentType::kSpot || !lightc->getShadowEnabled())
  405. {
  406. continue;
  407. }
  408. // Allocate tile
  409. U32 hierarchy;
  410. chooseDetail(cameraOrigin, *lightc, hierarchy);
  411. UVec4 atlasViewport;
  412. const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport);
  413. if(!!(result & TileAllocatorResult2::kAllocationSucceded))
  414. {
  415. // All good, update the light
  416. if(!(result & TileAllocatorResult2::kTileCached))
  417. {
  418. const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
  419. const Vec4 uvViewport = Vec4(atlasViewport) / atlasResolution;
  420. lightc->setShadowAtlasUvViewports({&uvViewport, 1});
  421. }
  422. // Vis testing
  423. const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
  424. FrustumGpuVisibilityInput visIn;
  425. visIn.m_passesName = "Shadows visibility: Spot light";
  426. visIn.m_technique = RenderingTechnique::kDepth;
  427. visIn.m_lodReferencePoint = cameraOrigin;
  428. visIn.m_lodDistances = lodDistances;
  429. visIn.m_rgraph = &rgraph;
  430. visIn.m_viewProjectionMatrix = lightc->getSpotLightViewProjectionMatrix();
  431. GpuVisibilityOutput visOut;
  432. getRenderer().getGpuVisibility().populateRenderGraph(visIn, visOut);
  433. // Add work
  434. ViewportWorkItem& work = *workItems.emplaceBack();
  435. work.m_viewProjMat = lightc->getSpotLightViewProjectionMatrix();
  436. work.m_viewMat = lightc->getSpotLightViewMatrix();
  437. work.m_viewport = atlasViewport;
  438. work.m_visOut = visOut;
  439. }
  440. else
  441. {
  442. // Doesn't have renderables or the allocation failed, won't be a shadow caster
  443. lightc->setShadowAtlasUvViewports({});
  444. }
  445. }
  446. // Move the work to the context
  447. if(workItems.getSize())
  448. {
  449. // All good, store the work items for the threads to pick up
  450. workItems.moveAndReset(m_runCtx.m_workItems);
  451. }
  452. else
  453. {
  454. m_runCtx.m_workItems = {};
  455. }
  456. }
  457. void ShadowMapping::runShadowMapping(RenderPassWorkContext& rgraphCtx)
  458. {
  459. ANKI_ASSERT(m_runCtx.m_workItems.getSize());
  460. ANKI_TRACE_SCOPED_EVENT(RSm);
  461. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  462. cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  463. for(ViewportWorkItem& work : m_runCtx.m_workItems)
  464. {
  465. // Set state
  466. cmdb.setViewport(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  467. cmdb.setScissor(work.m_viewport[0], work.m_viewport[1], work.m_viewport[2], work.m_viewport[3]);
  468. // Clear the depth buffer
  469. {
  470. cmdb.bindShaderProgram(m_clearDepthGrProg.get());
  471. cmdb.setDepthCompareOperation(CompareOperation::kAlways);
  472. cmdb.setPolygonOffset(0.0f, 0.0f);
  473. cmdb.draw(PrimitiveTopology::kTriangles, 3, 1);
  474. // Restore state
  475. cmdb.setDepthCompareOperation(CompareOperation::kLess);
  476. cmdb.setPolygonOffset(kShadowsPolygonOffsetFactor, kShadowsPolygonOffsetUnits);
  477. }
  478. RenderableDrawerArguments args;
  479. args.m_renderingTechinuqe = RenderingTechnique::kDepth;
  480. args.m_viewMatrix = work.m_viewMat;
  481. args.m_cameraTransform = Mat3x4::getIdentity(); // Don't care
  482. args.m_viewProjectionMatrix = work.m_viewProjMat;
  483. args.m_previousViewProjectionMatrix = Mat4::getIdentity(); // Don't care
  484. args.m_sampler = getRenderer().getSamplers().m_trilinearRepeatAniso.get();
  485. args.fillMdi(work.m_visOut);
  486. getRenderer().getSceneDrawer().drawMdi(args, cmdb);
  487. }
  488. }
  489. } // end namespace anki