2
0

BsShadowRendering.cpp 25 KB

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