BsShadowRendering.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsShadowRendering.h"
  4. #include "BsRendererView.h"
  5. #include "BsRendererScene.h"
  6. #include "BsLight.h"
  7. #include "BsRendererUtility.h"
  8. #include "BsGpuParamsSet.h"
  9. #include "BsMesh.h"
  10. #include "BsCamera.h"
  11. #include "BsBitwise.h"
  12. namespace bs { namespace ct
  13. {
  14. ShadowParamsDef gShadowParamsDef;
  15. ShadowDepthNormalMat::ShadowDepthNormalMat()
  16. { }
  17. void ShadowDepthNormalMat::_initDefines(ShaderDefines& defines)
  18. {
  19. // No defines
  20. }
  21. void ShadowDepthNormalMat::bind(const SPtr<GpuParamBlockBuffer>& shadowParams)
  22. {
  23. mParamsSet->setParamBlockBuffer("ShadowParams", shadowParams);
  24. gRendererUtility().setPass(mMaterial);
  25. }
  26. void ShadowDepthNormalMat::setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams)
  27. {
  28. mParamsSet->setParamBlockBuffer("PerObject", perObjectParams);
  29. gRendererUtility().setPassParams(mParamsSet);
  30. }
  31. ShadowDepthDirectionalMat::ShadowDepthDirectionalMat()
  32. { }
  33. void ShadowDepthDirectionalMat::_initDefines(ShaderDefines& defines)
  34. {
  35. // No defines
  36. }
  37. void ShadowDepthDirectionalMat::bind(const SPtr<GpuParamBlockBuffer>& shadowParams)
  38. {
  39. mParamsSet->setParamBlockBuffer("ShadowParams", shadowParams);
  40. gRendererUtility().setPass(mMaterial);
  41. }
  42. void ShadowDepthDirectionalMat::setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams)
  43. {
  44. mParamsSet->setParamBlockBuffer("PerObject", perObjectParams);
  45. gRendererUtility().setPassParams(mParamsSet);
  46. }
  47. ShadowCubeMatricesDef gShadowCubeMatricesDef;
  48. ShadowCubeMasksDef gShadowCubeMasksDef;
  49. ShadowDepthCubeMat::ShadowDepthCubeMat()
  50. { }
  51. void ShadowDepthCubeMat::_initDefines(ShaderDefines& defines)
  52. {
  53. // No defines
  54. }
  55. void ShadowDepthCubeMat::bind(const SPtr<GpuParamBlockBuffer>& shadowParams,
  56. const SPtr<GpuParamBlockBuffer>& shadowCubeMatrices)
  57. {
  58. mParamsSet->setParamBlockBuffer("ShadowParams", shadowParams);
  59. mParamsSet->setParamBlockBuffer("ShadowCubeMatrices", shadowCubeMatrices);
  60. gRendererUtility().setPass(mMaterial);
  61. }
  62. void ShadowDepthCubeMat::setPerObjectBuffer(const SPtr<GpuParamBlockBuffer>& perObjectParams,
  63. const SPtr<GpuParamBlockBuffer>& shadowCubeMasks)
  64. {
  65. mParamsSet->setParamBlockBuffer("PerObject", perObjectParams);
  66. mParamsSet->setParamBlockBuffer("ShadowCubeMasks", shadowCubeMasks);
  67. gRendererUtility().setPassParams(mParamsSet);
  68. }
  69. void ShadowMapInfo::updateNormArea(UINT32 atlasSize)
  70. {
  71. normArea.x = area.x / (float)atlasSize;
  72. normArea.y = area.y / (float)atlasSize;
  73. normArea.width = area.width / (float)atlasSize;
  74. normArea.height = area.height / (float)atlasSize;
  75. }
  76. ShadowMapAtlas::ShadowMapAtlas(UINT32 size)
  77. :mLastUsedCounter(0)
  78. {
  79. mAtlas = GpuResourcePool::instance().get(
  80. POOLED_RENDER_TEXTURE_DESC::create2D(PF_D24S8, size, size, TU_DEPTHSTENCIL));
  81. }
  82. ShadowMapAtlas::~ShadowMapAtlas()
  83. {
  84. GpuResourcePool::instance().release(mAtlas);
  85. }
  86. bool ShadowMapAtlas::addMap(UINT32 size, Rect2I& area, UINT32 border)
  87. {
  88. UINT32 sizeWithBorder = size + border * 2;
  89. UINT32 x, y;
  90. if (!mLayout.addElement(sizeWithBorder, sizeWithBorder, x, y))
  91. return false;
  92. area.width = area.height = size;
  93. area.x = x + border;
  94. area.y = y + border;
  95. mLastUsedCounter = 0;
  96. return true;
  97. }
  98. void ShadowMapAtlas::clear()
  99. {
  100. mLayout.clear();
  101. mLastUsedCounter++;
  102. }
  103. bool ShadowMapAtlas::isEmpty() const
  104. {
  105. return mLayout.isEmpty();
  106. }
  107. SPtr<Texture> ShadowMapAtlas::getTexture() const
  108. {
  109. return mAtlas->texture;
  110. }
  111. SPtr<RenderTexture> ShadowMapAtlas::getTarget() const
  112. {
  113. return mAtlas->renderTexture;
  114. }
  115. ShadowMapBase::ShadowMapBase(UINT32 size)
  116. : mSize(size), mIsUsed(false), mLastUsedCounter (0)
  117. { }
  118. SPtr<Texture> ShadowMapBase::getTexture() const
  119. {
  120. return mShadowMap->texture;
  121. }
  122. ShadowCubemap::ShadowCubemap(UINT32 size)
  123. :ShadowMapBase(size)
  124. {
  125. mShadowMap = GpuResourcePool::instance().get(
  126. POOLED_RENDER_TEXTURE_DESC::createCube(PF_D24S8, size, size, TU_DEPTHSTENCIL));
  127. RENDER_TEXTURE_DESC rtDesc;
  128. rtDesc.depthStencilSurface.texture = mShadowMap->texture;
  129. rtDesc.depthStencilSurface.numFaces = 6;
  130. }
  131. ShadowCubemap::~ShadowCubemap()
  132. {
  133. GpuResourcePool::instance().release(mShadowMap);
  134. }
  135. SPtr<RenderTexture> ShadowCubemap::getTarget() const
  136. {
  137. return mShadowMap->renderTexture;
  138. }
  139. ShadowCascadedMap::ShadowCascadedMap(UINT32 size)
  140. :ShadowMapBase(size)
  141. {
  142. mShadowMap = GpuResourcePool::instance().get(
  143. POOLED_RENDER_TEXTURE_DESC::create2D(PF_D24S8, size, size, TU_DEPTHSTENCIL, 0, false, NUM_CASCADE_SPLITS));
  144. RENDER_TEXTURE_DESC rtDesc;
  145. rtDesc.depthStencilSurface.texture = mShadowMap->texture;
  146. rtDesc.depthStencilSurface.numFaces = 1;
  147. for (int i = 0; i < NUM_CASCADE_SPLITS; ++i)
  148. {
  149. rtDesc.depthStencilSurface.face = i;
  150. mTargets[i] = RenderTexture::create(rtDesc);
  151. }
  152. }
  153. ShadowCascadedMap::~ShadowCascadedMap()
  154. {
  155. GpuResourcePool::instance().release(mShadowMap);
  156. }
  157. SPtr<RenderTexture> ShadowCascadedMap::getTarget(UINT32 cascadeIdx) const
  158. {
  159. return mTargets[cascadeIdx];
  160. }
  161. const UINT32 ShadowRendering::MAX_ATLAS_SIZE = 8192;
  162. const UINT32 ShadowRendering::MAX_UNUSED_FRAMES = 60;
  163. const UINT32 ShadowRendering::MIN_SHADOW_MAP_SIZE = 32;
  164. const UINT32 ShadowRendering::SHADOW_MAP_FADE_SIZE = 64;
  165. const UINT32 ShadowRendering::SHADOW_MAP_BORDER = 4;
  166. ShadowRendering::ShadowRendering(UINT32 shadowMapSize)
  167. : mShadowMapSize(shadowMapSize)
  168. { }
  169. void ShadowRendering::setShadowMapSize(UINT32 size)
  170. {
  171. if (mShadowMapSize == size)
  172. return;
  173. mCascadedShadowMaps.clear();
  174. mDynamicShadowMaps.clear();
  175. mShadowCubemaps.clear();
  176. }
  177. void ShadowRendering::renderShadowMaps(RendererScene& scene, const FrameInfo& frameInfo)
  178. {
  179. // Note: Currently all shadows are dynamic and are rebuilt every frame. I should later added support for static
  180. // shadow maps which can be used for immovable lights. Such a light can then maintain a set of shadow maps,
  181. // one of which is static and only effects the static geometry, while the rest are per-object shadow maps used
  182. // for dynamic objects. Then only a small subset of geometry needs to be redrawn, instead of everything.
  183. // Note: Add support for per-object shadows and a way to force a renderable to use per-object shadows. This can be
  184. // used for adding high quality shadows on specific objects (e.g. important characters during cinematics).
  185. const SceneInfo& sceneInfo = scene.getSceneInfo();
  186. // Clear all dynamic light atlases
  187. mSpotLightShadowInfos.clear();
  188. mRadialLightShadowInfos.clear();
  189. mSpotLightShadowOptions.clear();
  190. mRadialLightShadowOptions.clear();
  191. for (auto& entry : mCascadedShadowMaps)
  192. entry.clear();
  193. for (auto& entry : mDynamicShadowMaps)
  194. entry.clear();
  195. for (auto& entry : mShadowCubemaps)
  196. entry.clear();
  197. // Determine shadow map sizes and sort them
  198. for (UINT32 i = 0; i < (UINT32)sceneInfo.spotLights.size(); ++i)
  199. {
  200. scene.setLightShadowMapIdx(i, LightType::Spot, -1);
  201. // Note: I'm using visibility across all views, while I could be using visibility for every view individually,
  202. // if I kept that information somewhere
  203. if (!sceneInfo.spotLightVisibility[i])
  204. continue;
  205. const RendererLight& light = sceneInfo.spotLights[i];
  206. mSpotLightShadowOptions.push_back(ShadowMapOptions());
  207. ShadowMapOptions& options = mSpotLightShadowOptions.back();
  208. options.lightIdx = i;
  209. calcShadowMapProperties(light, scene, options.mapSize, options.fadePercent);
  210. }
  211. for (UINT32 i = 0; i < (UINT32)sceneInfo.radialLights.size(); ++i)
  212. {
  213. scene.setLightShadowMapIdx(i, LightType::Radial, -1);
  214. // Note: I'm using visibility across all views, while I could be using visibility for every view individually,
  215. // if I kept that information somewhere
  216. if (!sceneInfo.radialLightVisibility[i])
  217. continue;
  218. const RendererLight& light = sceneInfo.radialLights[i];
  219. mRadialLightShadowOptions.push_back(ShadowMapOptions());
  220. ShadowMapOptions& options = mRadialLightShadowOptions.back();
  221. options.lightIdx = i;
  222. calcShadowMapProperties(light, scene, options.mapSize, options.fadePercent);
  223. }
  224. // Sort spot lights by size so they fit neatly in the texture atlas
  225. std::sort(mSpotLightShadowOptions.begin(), mSpotLightShadowOptions.end(),
  226. [](const ShadowMapOptions& a, const ShadowMapOptions& b) { return a.mapSize > b.mapSize; } );
  227. // Render shadow maps
  228. for (UINT32 i = 0; i < (UINT32)sceneInfo.directionalLights.size(); ++i)
  229. {
  230. scene.setLightShadowMapIdx(i, LightType::Directional, -1);
  231. for(auto& entry : sceneInfo.views)
  232. renderCascadedShadowMaps(*entry.second, sceneInfo.directionalLights[i], scene, frameInfo);
  233. }
  234. for(auto& entry : mSpotLightShadowOptions)
  235. {
  236. UINT32 lightIdx = entry.lightIdx;
  237. renderSpotShadowMaps(sceneInfo.spotLights[lightIdx], entry.mapSize, scene, frameInfo);
  238. }
  239. for (auto& entry : mRadialLightShadowOptions)
  240. {
  241. UINT32 lightIdx = entry.lightIdx;
  242. renderRadialShadowMaps(sceneInfo.radialLights[lightIdx], entry.mapSize, scene, frameInfo);
  243. }
  244. // Deallocate unused textures
  245. for(auto iter = mDynamicShadowMaps.begin(); iter != mDynamicShadowMaps.end(); ++iter)
  246. {
  247. if(iter->getLastUsedCounter() >= MAX_UNUSED_FRAMES)
  248. {
  249. // These are always populated in order, so we can assume all following atlases are also empty
  250. mDynamicShadowMaps.erase(iter, mDynamicShadowMaps.end());
  251. break;
  252. }
  253. }
  254. for(auto iter = mCascadedShadowMaps.begin(); iter != mCascadedShadowMaps.end();)
  255. {
  256. if (iter->getLastUsedCounter() >= MAX_UNUSED_FRAMES)
  257. iter = mCascadedShadowMaps.erase(iter);
  258. else
  259. ++iter;
  260. }
  261. for(auto iter = mShadowCubemaps.begin(); iter != mShadowCubemaps.end();)
  262. {
  263. if (iter->getLastUsedCounter() >= MAX_UNUSED_FRAMES)
  264. iter = mShadowCubemaps.erase(iter);
  265. else
  266. ++iter;
  267. }
  268. }
  269. void ShadowRendering::renderCascadedShadowMaps(const RendererView& view, const RendererLight& rendererLight,
  270. RendererScene& scene, const FrameInfo& frameInfo)
  271. {
  272. // Note: Currently I'm using spherical bounds for the cascaded frustum which might result in non-optimal usage
  273. // of the shadow map. A different approach would be to generate a bounding box and then both adjust the aspect
  274. // ratio (and therefore dimensions) of the shadow map, as well as rotate the camera so the visible area best fits
  275. // in the map. It remains to be seen if this is viable.
  276. Light* light = rendererLight.internal;
  277. if (!light->getCastsShadow())
  278. return;
  279. const SceneInfo& sceneInfo = scene.getSceneInfo();
  280. RenderAPI& rapi = RenderAPI::instance();
  281. Vector3 lightDir = light->getRotation().zAxis();
  282. SPtr<GpuParamBlockBuffer> shadowParamsBuffer = gShadowParamsDef.createBuffer();
  283. // Assuming all cascaded shadow maps are the same size
  284. UINT32 mapSize = std::min(mShadowMapSize, MAX_ATLAS_SIZE);
  285. UINT32 mapIdx = -1;
  286. for (UINT32 i = 0; i < (UINT32)mCascadedShadowMaps.size(); i++)
  287. {
  288. ShadowCascadedMap& shadowMap = mCascadedShadowMaps[i];
  289. if (!shadowMap.isUsed() && shadowMap.getSize() == mapSize)
  290. {
  291. mapIdx = i;
  292. shadowMap.markAsUsed();
  293. break;
  294. }
  295. }
  296. if (mapIdx == -1)
  297. {
  298. mapIdx = (UINT32)mCascadedShadowMaps.size();
  299. mCascadedShadowMaps.push_back(ShadowCascadedMap(mapSize));
  300. ShadowCascadedMap& shadowMap = mCascadedShadowMaps.back();
  301. shadowMap.markAsUsed();
  302. }
  303. ShadowCascadedMap& shadowMap = mCascadedShadowMaps[mapIdx];
  304. Matrix4 viewMat = Matrix4::view(light->getPosition(), light->getRotation());
  305. for (int i = 0; i < NUM_CASCADE_SPLITS; ++i)
  306. {
  307. Sphere frustumBounds;
  308. ConvexVolume cascadeCullVolume = getCSMSplitFrustum(view, lightDir, i, NUM_CASCADE_SPLITS, frustumBounds);
  309. float orthoSize = frustumBounds.getRadius();
  310. Matrix4 proj = Matrix4::projectionOrthographic(-orthoSize, orthoSize, -orthoSize, orthoSize, 0.0f, 1000.0f);
  311. RenderAPI::instance().convertProjectionMatrix(proj, proj);
  312. Matrix4 viewProj = proj * viewMat;
  313. float nearDist = 0.05f;
  314. float farDist = light->getAttenuationRadius();
  315. float depthRange = farDist - nearDist;
  316. float depthBias = 0.0f; // TODO - determine optimal depth bias
  317. gShadowParamsDef.gDepthBias.set(shadowParamsBuffer, depthBias);
  318. gShadowParamsDef.gDepthRange.set(shadowParamsBuffer, depthRange);
  319. gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, viewProj);
  320. rapi.setRenderTarget(shadowMap.getTarget(i));
  321. rapi.clearRenderTarget(FBT_DEPTH);
  322. mDepthDirectionalMat.bind(shadowParamsBuffer);
  323. for (UINT32 j = 0; j < sceneInfo.renderables.size(); j++)
  324. {
  325. if (!cascadeCullVolume.intersects(sceneInfo.renderableCullInfos[j].bounds.getSphere()))
  326. continue;
  327. scene.prepareRenderable(j, frameInfo);
  328. RendererObject* renderable = sceneInfo.renderables[j];
  329. mDepthDirectionalMat.setPerObjectBuffer(renderable->perObjectParamBuffer);
  330. for (auto& element : renderable->elements)
  331. {
  332. if (element.morphVertexDeclaration == nullptr)
  333. gRendererUtility().draw(element.mesh, element.subMesh);
  334. else
  335. gRendererUtility().drawMorph(element.mesh, element.subMesh, element.morphShapeBuffer,
  336. element.morphVertexDeclaration);
  337. }
  338. }
  339. }
  340. }
  341. void ShadowRendering::renderSpotShadowMaps(const RendererLight& rendererLight, UINT32 mapSize, RendererScene& scene,
  342. const FrameInfo& frameInfo)
  343. {
  344. Light* light = rendererLight.internal;
  345. if (!light->getCastsShadow())
  346. return;
  347. const SceneInfo& sceneInfo = scene.getSceneInfo();
  348. SPtr<GpuParamBlockBuffer> shadowParamsBuffer = gShadowParamsDef.createBuffer();
  349. ShadowMapInfo mapInfo;
  350. bool foundSpace = false;
  351. for (UINT32 i = 0; i < (UINT32)mDynamicShadowMaps.size(); i++)
  352. {
  353. ShadowMapAtlas& atlas = mDynamicShadowMaps[i];
  354. if (atlas.addMap(mapSize, mapInfo.area, SHADOW_MAP_BORDER))
  355. {
  356. mapInfo.atlasIdx = i;
  357. foundSpace = true;
  358. break;
  359. }
  360. }
  361. if (!foundSpace)
  362. {
  363. mapInfo.atlasIdx = (UINT32)mDynamicShadowMaps.size();
  364. mDynamicShadowMaps.push_back(ShadowMapAtlas(MAX_ATLAS_SIZE));
  365. ShadowMapAtlas& atlas = mDynamicShadowMaps.back();
  366. atlas.addMap(mapSize, mapInfo.area, SHADOW_MAP_BORDER);
  367. }
  368. mapInfo.updateNormArea(MAX_ATLAS_SIZE);
  369. ShadowMapAtlas& atlas = mDynamicShadowMaps[mapInfo.atlasIdx];
  370. RenderAPI& rapi = RenderAPI::instance();
  371. rapi.setRenderTarget(atlas.getTarget());
  372. rapi.setViewport(mapInfo.normArea);
  373. rapi.clearViewport(FBT_DEPTH);
  374. float nearDist = 0.05f;
  375. float farDist = light->getAttenuationRadius();
  376. float depthRange = farDist - nearDist;
  377. float depthBias = 0.0f; // TODO - determine optimal depth bias
  378. Matrix4 view = Matrix4::view(light->getPosition(), light->getRotation());
  379. Matrix4 proj = Matrix4::projectionPerspective(light->getSpotAngle(), 1.0f, 0.05f, light->getAttenuationRadius());
  380. RenderAPI::instance().convertProjectionMatrix(proj, proj);
  381. Matrix4 viewProj = proj * view;
  382. gShadowParamsDef.gDepthBias.set(shadowParamsBuffer, depthBias);
  383. gShadowParamsDef.gDepthRange.set(shadowParamsBuffer, depthRange);
  384. gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, viewProj);
  385. mDepthNormalMat.bind(shadowParamsBuffer);
  386. ConvexVolume localFrustum = ConvexVolume(proj);
  387. const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
  388. Matrix4 worldMatrix = view.transpose();
  389. Vector<Plane> worldPlanes(frustumPlanes.size());
  390. UINT32 j = 0;
  391. for (auto& plane : frustumPlanes)
  392. {
  393. worldPlanes[j] = worldMatrix.multiplyAffine(plane);
  394. j++;
  395. }
  396. ConvexVolume worldFrustum(worldPlanes);
  397. for (UINT32 i = 0; i < sceneInfo.renderables.size(); i++)
  398. {
  399. if (!worldFrustum.intersects(sceneInfo.renderableCullInfos[i].bounds.getSphere()))
  400. continue;
  401. scene.prepareRenderable(i, frameInfo);
  402. RendererObject* renderable = sceneInfo.renderables[i];
  403. mDepthNormalMat.setPerObjectBuffer(renderable->perObjectParamBuffer);
  404. for (auto& element : renderable->elements)
  405. {
  406. if (element.morphVertexDeclaration == nullptr)
  407. gRendererUtility().draw(element.mesh, element.subMesh);
  408. else
  409. gRendererUtility().drawMorph(element.mesh, element.subMesh, element.morphShapeBuffer,
  410. element.morphVertexDeclaration);
  411. }
  412. }
  413. // Restore viewport
  414. rapi.setViewport(Rect2(0.0f, 0.0f, 1.0f, 1.0f));
  415. }
  416. void ShadowRendering::renderRadialShadowMaps(const RendererLight& rendererLight, UINT32 mapSize, RendererScene& scene,
  417. const FrameInfo& frameInfo)
  418. {
  419. Light* light = rendererLight.internal;
  420. if (!light->getCastsShadow())
  421. return;
  422. const SceneInfo& sceneInfo = scene.getSceneInfo();
  423. SPtr<GpuParamBlockBuffer> shadowParamsBuffer = gShadowParamsDef.createBuffer();
  424. SPtr<GpuParamBlockBuffer> shadowCubeMatricesBuffer = gShadowCubeMatricesDef.createBuffer();
  425. SPtr<GpuParamBlockBuffer> shadowCubeMasksBuffer = gShadowCubeMasksDef.createBuffer();
  426. UINT32 mapIdx = -1;
  427. for (UINT32 i = 0; i < (UINT32)mShadowCubemaps.size(); i++)
  428. {
  429. ShadowCubemap& cubemap = mShadowCubemaps[i];
  430. if (!cubemap.isUsed() && cubemap.getSize() == mapSize)
  431. {
  432. mapIdx = i;
  433. cubemap.markAsUsed();
  434. break;
  435. }
  436. }
  437. if (mapIdx == -1)
  438. {
  439. mapIdx = (UINT32)mShadowCubemaps.size();
  440. mShadowCubemaps.push_back(ShadowCubemap(mapSize));
  441. ShadowCubemap& cubemap = mShadowCubemaps.back();
  442. cubemap.markAsUsed();
  443. }
  444. ShadowCubemap& cubemap = mShadowCubemaps[mapIdx];
  445. float nearDist = 0.05f;
  446. float farDist = light->getAttenuationRadius();
  447. float depthRange = farDist - nearDist;
  448. float depthBias = 0.0f; // TODO - determine optimal depth bias
  449. Matrix4 proj = Matrix4::projectionPerspective(Degree(90.0f), 1.0f, 0.05f, light->getAttenuationRadius());
  450. RenderAPI::instance().convertProjectionMatrix(proj, proj);
  451. ConvexVolume localFrustum(proj);
  452. gShadowParamsDef.gDepthBias.set(shadowParamsBuffer, depthBias);
  453. gShadowParamsDef.gDepthRange.set(shadowParamsBuffer, depthRange);
  454. gShadowParamsDef.gMatViewProj.set(shadowParamsBuffer, Matrix4::IDENTITY);
  455. Matrix4 viewOffsetMat = Matrix4::translation(-light->getPosition());
  456. ConvexVolume frustums[6];
  457. Vector<Plane> boundingPlanes;
  458. for (UINT32 i = 0; i < 6; i++)
  459. {
  460. // Calculate view matrix
  461. Vector3 forward;
  462. Vector3 up = Vector3::UNIT_Y;
  463. switch (i)
  464. {
  465. case CF_PositiveX:
  466. forward = Vector3::UNIT_X;
  467. break;
  468. case CF_NegativeX:
  469. forward = -Vector3::UNIT_X;
  470. break;
  471. case CF_PositiveY:
  472. forward = Vector3::UNIT_Y;
  473. up = -Vector3::UNIT_Z;
  474. break;
  475. case CF_NegativeY:
  476. forward = Vector3::UNIT_X;
  477. up = Vector3::UNIT_Z;
  478. break;
  479. case CF_PositiveZ:
  480. forward = Vector3::UNIT_Z;
  481. break;
  482. case CF_NegativeZ:
  483. forward = -Vector3::UNIT_Z;
  484. break;
  485. }
  486. Vector3 right = Vector3::cross(up, forward);
  487. Matrix3 viewRotationMat = Matrix3(right, up, forward);
  488. Matrix4 view = Matrix4(viewRotationMat) * viewOffsetMat;
  489. gShadowCubeMatricesDef.gFaceVPMatrices.set(shadowCubeMatricesBuffer, proj * view, i);
  490. // Calculate world frustum for culling
  491. const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
  492. Matrix4 worldMatrix = view.transpose();
  493. Vector<Plane> worldPlanes(frustumPlanes.size());
  494. UINT32 j = 0;
  495. for (auto& plane : frustumPlanes)
  496. {
  497. worldPlanes[j] = worldMatrix.multiplyAffine(plane);
  498. j++;
  499. }
  500. frustums[i] = ConvexVolume(worldPlanes);
  501. // Register far plane of all frustums
  502. boundingPlanes.push_back(worldPlanes.back());
  503. }
  504. RenderAPI& rapi = RenderAPI::instance();
  505. rapi.setRenderTarget(cubemap.getTarget());
  506. rapi.clearRenderTarget(FBT_DEPTH);
  507. mDepthCubeMat.bind(shadowParamsBuffer, shadowCubeMatricesBuffer);
  508. // First cull against a global volume
  509. ConvexVolume boundingVolume(boundingPlanes);
  510. for (UINT32 i = 0; i < sceneInfo.renderables.size(); i++)
  511. {
  512. const Sphere& bounds = sceneInfo.renderableCullInfos[i].bounds.getSphere();
  513. if (!boundingVolume.intersects(bounds))
  514. continue;
  515. scene.prepareRenderable(i, frameInfo);
  516. for(UINT32 j = 0; j < 6; j++)
  517. {
  518. int mask = frustums->intersects(bounds) ? 1 : 0;
  519. gShadowCubeMasksDef.gFaceMasks.set(shadowCubeMasksBuffer, mask, j);
  520. }
  521. RendererObject* renderable = sceneInfo.renderables[i];
  522. mDepthCubeMat.setPerObjectBuffer(renderable->perObjectParamBuffer, shadowCubeMasksBuffer);
  523. for (auto& element : renderable->elements)
  524. {
  525. if (element.morphVertexDeclaration == nullptr)
  526. gRendererUtility().draw(element.mesh, element.subMesh);
  527. else
  528. gRendererUtility().drawMorph(element.mesh, element.subMesh, element.morphShapeBuffer,
  529. element.morphVertexDeclaration);
  530. }
  531. }
  532. }
  533. void ShadowRendering::calcShadowMapProperties(const RendererLight& light, RendererScene& scene, UINT32& size,
  534. float& fadePercent) const
  535. {
  536. const SceneInfo& sceneInfo = scene.getSceneInfo();
  537. // Find a view in which the light has the largest radius
  538. float maxRadiusPercent;
  539. for (auto& entry : sceneInfo.views)
  540. {
  541. const RendererViewProperties& viewProps = entry.second->getProperties();
  542. float viewScaleX = viewProps.projTransform[0][0] * 0.5f;
  543. float viewScaleY = viewProps.projTransform[1][1] * 0.5f;
  544. float viewScale = std::max(viewScaleX, viewScaleY);
  545. const Matrix4& viewVP = viewProps.viewProjTransform;
  546. Vector4 lightClipPos = viewVP.multiply(Vector4(light.internal->getPosition(), 1.0f));
  547. float radiusNDC = light.internal->getBounds().getRadius() / std::max(lightClipPos.w, 1.0f);
  548. // Radius of light bounds in percent of the view surface
  549. float radiusPercent = radiusNDC * viewScale;
  550. maxRadiusPercent = std::max(maxRadiusPercent, radiusPercent);
  551. }
  552. // If light fully (or nearly fully) covers the screen, use full shadow map resolution, otherwise
  553. // scale it down to smaller power of two, while clamping to minimal allowed resolution
  554. float optimalMapSize = mShadowMapSize * maxRadiusPercent;
  555. UINT32 effectiveMapSize = Bitwise::nextPow2((UINT32)optimalMapSize);
  556. effectiveMapSize = Math::clamp(effectiveMapSize, MIN_SHADOW_MAP_SIZE, mShadowMapSize);
  557. // Leave room for border
  558. size = std::max(effectiveMapSize - 2 * SHADOW_MAP_BORDER, 1u);
  559. // Determine if the shadow should fade out
  560. fadePercent = Math::lerp01(optimalMapSize, (float)MIN_SHADOW_MAP_SIZE, (float)SHADOW_MAP_FADE_SIZE);
  561. }
  562. ConvexVolume ShadowRendering::getCSMSplitFrustum(const RendererView& view, const Vector3& lightDir, UINT32 cascade,
  563. UINT32 numCascades, Sphere& outBounds)
  564. {
  565. // Determine split range
  566. float splitNear = getCSMSplitDistance(view, cascade, numCascades);
  567. float splitFar = getCSMSplitDistance(view, cascade + 1, numCascades);
  568. // Calculate the eight vertices of the split frustum
  569. auto& viewProps = view.getProperties();
  570. const Matrix4& projMat = viewProps.projTransform;
  571. float aspect;
  572. float nearHalfWidth, nearHalfHeight;
  573. float farHalfWidth, farHalfHeight;
  574. if(viewProps.projType == PT_PERSPECTIVE)
  575. {
  576. aspect = projMat[0][0] / projMat[1][1];
  577. float tanHalfFOV = 1.0f / projMat[0][0];
  578. nearHalfWidth = splitNear * tanHalfFOV;
  579. nearHalfHeight = nearHalfWidth * aspect;
  580. farHalfWidth = splitFar * tanHalfFOV;
  581. farHalfHeight = farHalfWidth * aspect;
  582. }
  583. else
  584. {
  585. aspect = projMat[0][0] / projMat[1][1];
  586. nearHalfWidth = farHalfWidth = projMat[0][0] / 4.0f;
  587. nearHalfHeight = farHalfHeight = projMat[1][1] / 4.0f;
  588. }
  589. const Matrix4& viewMat = viewProps.viewTransform;
  590. Vector3 cameraRight = Vector3(viewMat[0]);
  591. Vector3 cameraUp = Vector3(viewMat[1]);
  592. const Vector3& viewOrigin = viewProps.viewOrigin;
  593. const Vector3& viewDir = viewProps.viewDirection;
  594. Vector3 frustumVerts[] =
  595. {
  596. viewOrigin + viewDir * splitNear - cameraRight * nearHalfWidth + cameraUp * nearHalfHeight, // Near, left, top
  597. viewOrigin + viewDir * splitNear + cameraRight * nearHalfWidth + cameraUp * nearHalfHeight, // Near, right, top
  598. viewOrigin + viewDir * splitNear + cameraRight * nearHalfWidth - cameraUp * nearHalfHeight, // Near, right, bottom
  599. viewOrigin + viewDir * splitNear - cameraRight * nearHalfWidth - cameraUp * nearHalfHeight, // Near, left, bottom
  600. viewOrigin + viewDir * splitFar - cameraRight * farHalfWidth + cameraUp * farHalfHeight, // Far, left, top
  601. viewOrigin + viewDir * splitFar + cameraRight * farHalfWidth + cameraUp * farHalfHeight, // Far, right, top
  602. viewOrigin + viewDir * splitFar + cameraRight * farHalfWidth - cameraUp * farHalfHeight, // Far, right, bottom
  603. viewOrigin + viewDir * splitFar - cameraRight * farHalfWidth - cameraUp * farHalfHeight, // Far, left, bottom
  604. };
  605. // Calculate the bounding sphere of the frustum
  606. float diagonalNearSq = nearHalfWidth * nearHalfWidth + nearHalfHeight * nearHalfHeight;
  607. float diagonalFarSq = farHalfWidth * farHalfWidth + farHalfHeight * farHalfHeight;
  608. float length = splitFar - splitNear;
  609. float offset = (diagonalNearSq - diagonalFarSq) / 2 * length + length * 0.5f;
  610. float distToCenter = Math::clamp(splitFar - offset, splitNear, splitFar);
  611. Vector3 center = viewOrigin + viewDir * distToCenter;
  612. float radius = 0.0f;
  613. for (auto& entry : frustumVerts)
  614. radius = std::max(radius, center.squaredDistance(entry));
  615. radius = std::max(sqrt(radius), 1.0f);
  616. outBounds = Sphere(center, radius);
  617. // Generate light frustum planes
  618. Plane viewPlanes[6];
  619. viewPlanes[FRUSTUM_PLANE_NEAR] = Plane(frustumVerts[0], frustumVerts[1], frustumVerts[2]);
  620. viewPlanes[FRUSTUM_PLANE_FAR] = Plane(frustumVerts[5], frustumVerts[4], frustumVerts[7]);
  621. viewPlanes[FRUSTUM_PLANE_LEFT] = Plane(frustumVerts[4], frustumVerts[0], frustumVerts[3]);
  622. viewPlanes[FRUSTUM_PLANE_RIGHT] = Plane(frustumVerts[1], frustumVerts[5], frustumVerts[6]);
  623. viewPlanes[FRUSTUM_PLANE_TOP] = Plane(frustumVerts[4], frustumVerts[5], frustumVerts[1]);
  624. viewPlanes[FRUSTUM_PLANE_BOTTOM] = Plane(frustumVerts[3], frustumVerts[2], frustumVerts[6]);
  625. Vector<Plane> lightVolume;
  626. //// Add camera's planes facing towards the lights (forming the back of the volume)
  627. for(auto& entry : viewPlanes)
  628. {
  629. if (entry.normal.dot(lightDir) < 0.0f)
  630. lightVolume.push_back(entry);
  631. }
  632. //// Determine edge planes by testing adjacent planes with different facing
  633. ////// Pairs of frustum planes that share an edge
  634. UINT32 adjacentPlanes[][2] =
  635. {
  636. { FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_LEFT },
  637. { FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_RIGHT },
  638. { FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_TOP },
  639. { FRUSTUM_PLANE_NEAR, FRUSTUM_PLANE_BOTTOM },
  640. { FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_LEFT },
  641. { FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_RIGHT },
  642. { FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_TOP },
  643. { FRUSTUM_PLANE_FAR, FRUSTUM_PLANE_BOTTOM },
  644. { FRUSTUM_PLANE_LEFT, FRUSTUM_PLANE_TOP },
  645. { FRUSTUM_PLANE_TOP, FRUSTUM_PLANE_RIGHT },
  646. { FRUSTUM_PLANE_RIGHT, FRUSTUM_PLANE_BOTTOM },
  647. { FRUSTUM_PLANE_BOTTOM, FRUSTUM_PLANE_LEFT },
  648. };
  649. ////// Vertex indices of edges on the boundary between two planes
  650. UINT32 sharedEdges[][2] =
  651. {
  652. { 3, 0 },{ 1, 2 },{ 0, 1 },{ 2, 3 },
  653. { 4, 7 },{ 6, 5 },{ 5, 4 },{ 7, 6 },
  654. { 4, 0 },{ 5, 1 },{ 6, 2 },{ 7, 3 }
  655. };
  656. for(UINT32 i = 0; i < 12; i++)
  657. {
  658. const Plane& planeA = viewPlanes[adjacentPlanes[i][0]];
  659. const Plane& planeB = viewPlanes[adjacentPlanes[i][1]];
  660. float dotA = planeA.normal.dot(lightDir);
  661. float dotB = planeB.normal.dot(lightDir);
  662. if((dotA * dotB) < 0.0f)
  663. {
  664. const Vector3& vertA = frustumVerts[sharedEdges[i][0]];
  665. const Vector3& vertB = frustumVerts[sharedEdges[i][1]];
  666. Vector3 vertC = vertA + lightDir;
  667. if (dotA >= 0.0f)
  668. lightVolume.push_back(Plane(vertA, vertB, vertC));
  669. else
  670. lightVolume.push_back(Plane(vertB, vertA, vertC));
  671. }
  672. }
  673. return ConvexVolume(lightVolume);
  674. }
  675. float ShadowRendering::getCSMSplitDistance(const RendererView& view, UINT32 index, UINT32 numCascades)
  676. {
  677. // Determines the size of each subsequent cascade split. Value of 1 means the cascades will be linearly split.
  678. // Value of 2 means each subsequent split will be twice the size of the previous one. Valid range is roughly
  679. // [1, 4].
  680. // Note: Make this an adjustable property?
  681. const static float DISTRIBUTON_EXPONENT = 1.0f;
  682. // First determine the scale of the split, relative to the entire range
  683. float scaleModifier = 1.0f;
  684. float scale = 0.0f;
  685. float totalScale = 0.0f;
  686. //// Split 0 corresponds to near plane
  687. if (index > 0)
  688. {
  689. for (UINT32 i = 0; i < numCascades; i++)
  690. {
  691. if (i < index)
  692. scale += scaleModifier;
  693. totalScale += scaleModifier;
  694. scaleModifier *= DISTRIBUTON_EXPONENT;
  695. }
  696. }
  697. scale = scale / totalScale;
  698. // Calculate split distance in Z
  699. auto& viewProps = view.getProperties();
  700. float near = viewProps.nearPlane;
  701. float far = viewProps.farPlane;
  702. return near + (far - near) * scale;
  703. }
  704. }}