Torque3D Documentation / _generateds / shadowMapPass.cpp

shadowMapPass.cpp

Engine/source/lighting/shadowMap/shadowMapPass.cpp

More...

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