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