shadowMapPass.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "lighting/shadowMap/shadowMapPass.h"
  24. #include "lighting/shadowMap/lightShadowMap.h"
  25. #include "lighting/shadowMap/shadowMapManager.h"
  26. #include "lighting/lightManager.h"
  27. #include "scene/sceneManager.h"
  28. #include "scene/sceneRenderState.h"
  29. #include "renderInstance/renderPassManager.h"
  30. #include "renderInstance/renderObjectMgr.h"
  31. #include "renderInstance/renderMeshMgr.h"
  32. #include "renderInstance/renderTerrainMgr.h"
  33. #include "renderInstance/renderImposterMgr.h"
  34. #include "core/util/safeDelete.h"
  35. #include "console/consoleTypes.h"
  36. #include "gfx/gfxTransformSaver.h"
  37. #include "gfx/gfxDebugEvent.h"
  38. #include "platform/platformTimer.h"
  39. #include "T3D/gameBase/gameConnection.h"
  40. const String ShadowMapPass::PassTypeName("ShadowMap");
  41. U32 ShadowMapPass::smActiveShadowMaps = 0;
  42. U32 ShadowMapPass::smUpdatedShadowMaps = 0;
  43. U32 ShadowMapPass::smNearShadowMaps = 0;
  44. U32 ShadowMapPass::smShadowMapsDrawCalls = 0;
  45. U32 ShadowMapPass::smShadowMapPolyCount = 0;
  46. U32 ShadowMapPass::smRenderTargetChanges = 0;
  47. U32 ShadowMapPass::smShadowPoolTexturesCount = 0.;
  48. F32 ShadowMapPass::smShadowPoolMemory = 0.0f;
  49. bool ShadowMapPass::smDisableShadows = false;
  50. bool ShadowMapPass::smDisableShadowsEditor = false;
  51. bool ShadowMapPass::smDisableShadowsPref = false;
  52. /// distance moved per frame before forcing a shadow update
  53. F32 ShadowMapPass::smShadowsTeleportDist = 4;
  54. /// angle turned per frame before forcing a shadow update
  55. F32 ShadowMapPass::smShadowsTurnRate = 1;
  56. /// We have a default 8ms render budget for shadow rendering.
  57. U32 ShadowMapPass::smRenderBudgetMs = 8;
  58. ShadowMapPass::ShadowMapPass(LightManager* lightManager, ShadowMapManager* shadowManager)
  59. {
  60. mLightManager = lightManager;
  61. mShadowManager = shadowManager;
  62. // Setup our render pass managers
  63. // Static
  64. mShadowRPM = new ShadowRenderPassManager();
  65. mShadowRPM->assignName( "ShadowRenderPassManager" );
  66. mShadowRPM->registerObject();
  67. Sim::getRootGroup()->addObject( mShadowRPM );
  68. mShadowRPM->addManager( new RenderMeshMgr(RenderPassManager::RIT_Mesh, 0.3f, 0.3f) );
  69. mShadowRPM->addManager( new RenderTerrainMgr( 0.5f, 0.5f ) );
  70. mShadowRPM->addManager( new RenderImposterMgr( 0.6f, 0.6f ) );
  71. // Dynamic
  72. mDynamicShadowRPM = new DynamicShadowRenderPassManager();
  73. mDynamicShadowRPM->assignName( "DynamicShadowRenderPassManager" );
  74. mDynamicShadowRPM->registerObject();
  75. Sim::getRootGroup()->addObject( mDynamicShadowRPM );
  76. mDynamicShadowRPM->addManager( new RenderMeshMgr(RenderPassManager::RIT_Mesh, 0.3f, 0.3f) );
  77. mDynamicShadowRPM->addManager( new RenderTerrainMgr( 0.5f, 0.5f ) );
  78. mDynamicShadowRPM->addManager( new RenderImposterMgr( 0.6f, 0.6f ) );
  79. mActiveLights = 0;
  80. mPrevCamPos = Point3F::Zero;
  81. mPrevCamRot = Point3F::Zero;
  82. mTimer = PlatformTimer::create();
  83. Con::addVariable( "$ShadowStats::activeMaps", TypeS32, &smActiveShadowMaps,
  84. "The shadow stats showing the active number of shadow maps.\n"
  85. "@ingroup AdvancedLighting\n" );
  86. Con::addVariable( "$ShadowStats::updatedMaps", TypeS32, &smUpdatedShadowMaps,
  87. "The shadow stats showing the number of shadow maps updated this frame.\n"
  88. "@ingroup AdvancedLighting\n" );
  89. Con::addVariable( "$ShadowStats::nearMaps", TypeS32, &smNearShadowMaps,
  90. "The shadow stats showing the number of shadow maps that are close enough to be updated very frame.\n"
  91. "@ingroup AdvancedLighting\n" );
  92. Con::addVariable( "$ShadowStats::drawCalls", TypeS32, &smShadowMapsDrawCalls,
  93. "The shadow stats showing the number of draw calls in shadow map renders for this frame.\n"
  94. "@ingroup AdvancedLighting\n" );
  95. Con::addVariable( "$ShadowStats::polyCount", TypeS32, &smShadowMapPolyCount,
  96. "The shadow stats showing the number of triangles in shadow map renders for this frame.\n"
  97. "@ingroup AdvancedLighting\n" );
  98. Con::addVariable( "$ShadowStats::rtChanges", TypeS32, &smRenderTargetChanges,
  99. "The shadow stats showing the number of render target changes for shadow maps in this frame.\n"
  100. "@ingroup AdvancedLighting\n" );
  101. Con::addVariable( "$ShadowStats::poolTexCount", TypeS32, &smShadowPoolTexturesCount,
  102. "The shadow stats showing the number of shadow textures in the shadow texture pool.\n"
  103. "@ingroup AdvancedLighting\n" );
  104. Con::addVariable( "$ShadowStats::poolTexMemory", TypeF32, &smShadowPoolMemory,
  105. "The shadow stats showing the approximate texture memory usage of the shadow map texture pool.\n"
  106. "@ingroup AdvancedLighting\n" );
  107. }
  108. ShadowMapPass::~ShadowMapPass()
  109. {
  110. SAFE_DELETE( mTimer );
  111. if ( mShadowRPM )
  112. mShadowRPM->deleteObject();
  113. if ( mDynamicShadowRPM )
  114. mDynamicShadowRPM->deleteObject();
  115. }
  116. void ShadowMapPass::render( SceneManager *sceneManager,
  117. const SceneRenderState *diffuseState,
  118. U32 objectMask )
  119. {
  120. PROFILE_SCOPE( ShadowMapPass_Render );
  121. // Prep some shadow rendering stats.
  122. smActiveShadowMaps = 0;
  123. smUpdatedShadowMaps = 0;
  124. smNearShadowMaps = 0;
  125. GFXDeviceStatistics stats;
  126. stats.start( GFX->getDeviceStatistics() );
  127. // NOTE: The lights were already registered by SceneManager.
  128. // Update mLights
  129. mLights.clear();
  130. mLightManager->getAllUnsortedLights( &mLights );
  131. mActiveLights = mLights.size();
  132. // Use the per-frame incremented time for
  133. // priority updates and to track when the
  134. // shadow was last updated.
  135. const U32 currTime = Sim::getCurrentTime();
  136. // First do a loop thru the lights setting up the shadow
  137. // info array for this pass.
  138. Vector<LightShadowMap*> shadowMaps;
  139. shadowMaps.reserve( mActiveLights * 2 );
  140. for ( U32 i = 0; i < mActiveLights; i++ )
  141. {
  142. ShadowMapParams *params = mLights[i]->getExtended<ShadowMapParams>();
  143. // Before we do anything... skip lights without shadows.
  144. if ( !mLights[i]->getCastShadows() || smDisableShadows )
  145. continue;
  146. // --- Static Shadow Map ---
  147. LightShadowMap *lsm = params->getOrCreateShadowMap();
  148. LightShadowMap *dlsm = params->getOrCreateShadowMap(true);
  149. // First check the visiblity query... if it wasn't
  150. // visible skip it.
  151. if(params->getOcclusionQuery()->getStatus(true) == GFXOcclusionQuery::Occluded)
  152. continue;
  153. // Any shadow that is visible is counted as being
  154. // active regardless if we update it or not.
  155. ++smActiveShadowMaps;
  156. // Do a priority update for this shadow.
  157. lsm->updatePriority(diffuseState, currTime);
  158. shadowMaps.push_back(lsm);
  159. // --- Dynamic Shadow Map ---
  160. // Any shadow that is visible is counted as being
  161. // active regardless if we update it or not.
  162. ++smActiveShadowMaps;
  163. // Do a priority update for this shadow.
  164. dlsm->updatePriority(diffuseState, currTime);
  165. shadowMaps.push_back( dlsm );
  166. }
  167. // Now sort the shadow info by priority.
  168. // andrewmac: tempoarily disabled until I find a better solution.
  169. //shadowMaps.sort( LightShadowMap::cmpPriority );
  170. GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render, ColorI::RED );
  171. // Use a timer for tracking our shadow rendering
  172. // budget to ensure a high precision results.
  173. mTimer->getElapsedMs();
  174. mTimer->reset();
  175. // Must have a connection and control object
  176. GameConnection* conn = GameConnection::getConnectionToServer();
  177. if (!conn)
  178. return;
  179. GameBase * control = dynamic_cast<GameBase*>(conn->getControlObject());
  180. if (!control)
  181. return;
  182. bool forceUpdate = false;
  183. //force an update if we're jumping around (respawning, ect)
  184. MatrixF curCamMatrix = control->getTransform();
  185. if (((curCamMatrix.getPosition() - mPrevCamPos).lenSquared() > mPow(smShadowsTeleportDist, 2)) || //update if we're teleporting
  186. ((curCamMatrix.getForwardVector() - mPrevCamRot).lenSquared() > mPow(smShadowsTurnRate*M_PI_F / 180, 2)) || //update if we're turning too fast
  187. (control->getCameraFov()) != mPrevCamFov) //update if we're zooming or unzooming
  188. forceUpdate = true;
  189. mPrevCamRot = curCamMatrix.getForwardVector();
  190. mPrevCamPos = curCamMatrix.getPosition();
  191. mPrevCamFov = control->getCameraFov();
  192. // 2 Shadow Maps per Light. This may fail.
  193. for ( U32 i = 0; i < shadowMaps.size(); i += 2 )
  194. {
  195. LightShadowMap *lsm = shadowMaps[i];
  196. LightShadowMap *dlsm = shadowMaps[i + 1];
  197. {
  198. GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render_Shadow, ColorI::RED );
  199. mShadowManager->setLightShadowMap(lsm);
  200. mShadowManager->setLightDynamicShadowMap( dlsm );
  201. lsm->render(mShadowRPM, diffuseState, false, forceUpdate);
  202. dlsm->render(mDynamicShadowRPM, diffuseState, true, forceUpdate);
  203. ++smUpdatedShadowMaps;
  204. }
  205. // View dependent shadows or ones that are covering the entire
  206. // screen are updated every frame no matter the time left in
  207. // our shadow rendering budget.
  208. if ( dlsm->isViewDependent() || dlsm->getLastScreenSize() >= 1.0f )
  209. {
  210. ++smNearShadowMaps;
  211. continue;
  212. }
  213. // See if we're over our frame budget for shadow
  214. // updates... give up completely in that case.
  215. if ( mTimer->getElapsedMs() > smRenderBudgetMs )
  216. break;
  217. }
  218. // Cleanup old unused textures.
  219. LightShadowMap::releaseUnusedTextures();
  220. // Update the stats.
  221. stats.end( GFX->getDeviceStatistics() );
  222. smShadowMapsDrawCalls = stats.mDrawCalls;
  223. smShadowMapPolyCount = stats.mPolyCount;
  224. smRenderTargetChanges = stats.mRenderTargetChanges;
  225. smShadowPoolTexturesCount = ShadowMapProfile.getStats().activeCount;
  226. smShadowPoolMemory = ( ShadowMapProfile.getStats().activeBytes / 1024.0f ) / 1024.0f;
  227. // The NULL here is importaint as having it around
  228. // will cause extra work in AdvancedLightManager::setLightInfo().
  229. mShadowManager->setLightShadowMap( NULL );
  230. mShadowManager->setLightDynamicShadowMap( NULL );
  231. }
  232. void ShadowRenderPassManager::addInst( RenderInst *inst )
  233. {
  234. PROFILE_SCOPE(ShadowRenderPassManager_addInst);
  235. if ( inst->type == RIT_Mesh )
  236. {
  237. MeshRenderInst *meshRI = static_cast<MeshRenderInst*>( inst );
  238. if ( !meshRI->matInst )
  239. return;
  240. const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
  241. if ( !mat->castsShadows() || mat->castsDynamicShadows() || mat->isTranslucent() )
  242. {
  243. // Do not add this instance, return here and avoid the default behavior
  244. // of calling up to Parent::addInst()
  245. return;
  246. }
  247. }
  248. Parent::addInst(inst);
  249. }
  250. void DynamicShadowRenderPassManager::addInst( RenderInst *inst )
  251. {
  252. PROFILE_SCOPE(DynamicShadowRenderPassManager_addInst);
  253. if ( inst->type == RIT_Mesh )
  254. {
  255. MeshRenderInst *meshRI = static_cast<MeshRenderInst*>( inst );
  256. if ( !meshRI->matInst )
  257. return;
  258. const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
  259. if ( !mat->castsShadows() || !mat->castsDynamicShadows() || mat->isTranslucent() )
  260. {
  261. // Do not add this instance, return here and avoid the default behavior
  262. // of calling up to Parent::addInst()
  263. return;
  264. }
  265. }
  266. Parent::addInst(inst);
  267. }