mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-13 03:33:48 +00:00
shadow caching
SPECIAL NOTE: highly suggest https://github.com/GarageGames/Torque3D/pull/1441 or a variation thereof to prevent debug spew and false-postives for occlusion results. With significant research, development and prototyping assistance from both @andr3wmac (shaders and partial hook work), and @LuisAntonRebollo (additional culling) System operates as follows: 1) materials are given an additional castDynamicShadows boolean entry. (Default at time of writing is true by request. Personal usage at time of writing defaults to false. value is default-initialized in materialDefinition.cpp. script/gui exposed) 2) lights are given a staticRefreshFreq and dynamicRefreshFreq (in milliseconds). script/gui exposed 3) materials are (effectively) sorted into dynamic and static shadowmap render lists based on flag. (see shadowMapPass.cpp) 4) initial shadowmaps are generated for each light and 'list'. 5) as each refreshFreq times out, the relevant shadowmap for a given light is refreshed. Special notes: dynamicRefreshFreq for all lights is set to a (script exposed) 8MS refresh timer. StaticRefreshFreq for the lions share of lights defaults to 250 MS (1/4 of a second) scattersky's embedded light, which is intended to operate in a mobile manner, defaults to 8 to reiterate, these are all customizable per-light via script/inspector gui in the case of alternate project needs.
This commit is contained in:
parent
2044b2691e
commit
2753f562e8
54 changed files with 1477 additions and 464 deletions
|
|
@ -55,6 +55,11 @@ bool ShadowMapPass::smDisableShadows = false;
|
|||
bool ShadowMapPass::smDisableShadowsEditor = false;
|
||||
bool ShadowMapPass::smDisableShadowsPref = false;
|
||||
|
||||
/// milliseconds before static redraw
|
||||
S32 ShadowMapPass::smStaticShadowUpdateFreq = 32;
|
||||
/// milliseconds before dynamic redraw
|
||||
S32 ShadowMapPass::smDynamicShadowUpdateFreq = 16;
|
||||
|
||||
/// We have a default 8ms render budget for shadow rendering.
|
||||
U32 ShadowMapPass::smRenderBudgetMs = 8;
|
||||
|
||||
|
|
@ -62,18 +67,27 @@ ShadowMapPass::ShadowMapPass(LightManager* lightManager, ShadowMapManager* shado
|
|||
{
|
||||
mLightManager = lightManager;
|
||||
mShadowManager = shadowManager;
|
||||
|
||||
// Setup our render pass managers
|
||||
|
||||
// Static
|
||||
mShadowRPM = new ShadowRenderPassManager();
|
||||
mShadowRPM->assignName( "ShadowRenderPassManager" );
|
||||
mShadowRPM->registerObject();
|
||||
Sim::getRootGroup()->addObject( mShadowRPM );
|
||||
|
||||
// Setup our render pass manager
|
||||
|
||||
mShadowRPM->addManager( new RenderMeshMgr(RenderPassManager::RIT_Mesh, 0.3f, 0.3f) );
|
||||
//mShadowRPM->addManager( new RenderObjectMgr() );
|
||||
mShadowRPM->addManager( new RenderTerrainMgr( 0.5f, 0.5f ) );
|
||||
mShadowRPM->addManager( new RenderImposterMgr( 0.6f, 0.6f ) );
|
||||
|
||||
// Dynamic
|
||||
mDynamicShadowRPM = new DynamicShadowRenderPassManager();
|
||||
mDynamicShadowRPM->assignName( "DynamicShadowRenderPassManager" );
|
||||
mDynamicShadowRPM->registerObject();
|
||||
Sim::getRootGroup()->addObject( mDynamicShadowRPM );
|
||||
mDynamicShadowRPM->addManager( new RenderMeshMgr(RenderPassManager::RIT_Mesh, 0.3f, 0.3f) );
|
||||
mDynamicShadowRPM->addManager( new RenderTerrainMgr( 0.5f, 0.5f ) );
|
||||
mDynamicShadowRPM->addManager( new RenderImposterMgr( 0.6f, 0.6f ) );
|
||||
|
||||
mActiveLights = 0;
|
||||
|
||||
mTimer = PlatformTimer::create();
|
||||
|
|
@ -117,6 +131,9 @@ ShadowMapPass::~ShadowMapPass()
|
|||
|
||||
if ( mShadowRPM )
|
||||
mShadowRPM->deleteObject();
|
||||
|
||||
if ( mDynamicShadowRPM )
|
||||
mDynamicShadowRPM->deleteObject();
|
||||
}
|
||||
|
||||
void ShadowMapPass::render( SceneManager *sceneManager,
|
||||
|
|
@ -147,7 +164,7 @@ void ShadowMapPass::render( SceneManager *sceneManager,
|
|||
// First do a loop thru the lights setting up the shadow
|
||||
// info array for this pass.
|
||||
Vector<LightShadowMap*> shadowMaps;
|
||||
shadowMaps.reserve( mActiveLights );
|
||||
shadowMaps.reserve( mActiveLights * 2 );
|
||||
for ( U32 i = 0; i < mActiveLights; i++ )
|
||||
{
|
||||
ShadowMapParams *params = mLights[i]->getExtended<ShadowMapParams>();
|
||||
|
|
@ -155,12 +172,14 @@ void ShadowMapPass::render( SceneManager *sceneManager,
|
|||
// Before we do anything... skip lights without shadows.
|
||||
if ( !mLights[i]->getCastShadows() || smDisableShadows )
|
||||
continue;
|
||||
|
||||
LightShadowMap *lsm = params->getOrCreateShadowMap();
|
||||
|
||||
// --- Static Shadow Map ---
|
||||
LightShadowMap *lsm = params->getOrCreateShadowMap();
|
||||
LightShadowMap *dlsm = params->getOrCreateShadowMap(true);
|
||||
|
||||
// First check the visiblity query... if it wasn't
|
||||
// visible skip it.
|
||||
if ( lsm->wasOccluded() )
|
||||
if (lsm->wasOccluded() || dlsm->wasOccluded())
|
||||
continue;
|
||||
|
||||
// Any shadow that is visible is counted as being
|
||||
|
|
@ -168,13 +187,25 @@ void ShadowMapPass::render( SceneManager *sceneManager,
|
|||
++smActiveShadowMaps;
|
||||
|
||||
// Do a priority update for this shadow.
|
||||
lsm->updatePriority( diffuseState, currTime );
|
||||
lsm->updatePriority(diffuseState, currTime);
|
||||
|
||||
shadowMaps.push_back( lsm );
|
||||
shadowMaps.push_back(lsm);
|
||||
|
||||
// --- Dynamic Shadow Map ---
|
||||
|
||||
// Any shadow that is visible is counted as being
|
||||
// active regardless if we update it or not.
|
||||
++smActiveShadowMaps;
|
||||
|
||||
// Do a priority update for this shadow.
|
||||
dlsm->updatePriority(diffuseState, currTime);
|
||||
|
||||
shadowMaps.push_back( dlsm );
|
||||
}
|
||||
|
||||
// Now sort the shadow info by priority.
|
||||
shadowMaps.sort( LightShadowMap::cmpPriority );
|
||||
// andrewmac: tempoarily disabled until I find a better solution.
|
||||
//shadowMaps.sort( LightShadowMap::cmpPriority );
|
||||
|
||||
GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render, ColorI::RED );
|
||||
|
||||
|
|
@ -183,22 +214,28 @@ void ShadowMapPass::render( SceneManager *sceneManager,
|
|||
mTimer->getElapsedMs();
|
||||
mTimer->reset();
|
||||
|
||||
for ( U32 i = 0; i < shadowMaps.size(); i++ )
|
||||
// 2 Shadow Maps per Light. This may fail.
|
||||
for ( U32 i = 0; i < shadowMaps.size(); i += 2 )
|
||||
{
|
||||
LightShadowMap *lsm = shadowMaps[i];
|
||||
LightShadowMap *lsm = shadowMaps[i];
|
||||
LightShadowMap *dlsm = shadowMaps[i + 1];
|
||||
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render_Shadow, ColorI::RED );
|
||||
|
||||
mShadowManager->setLightShadowMap( lsm );
|
||||
lsm->render( mShadowRPM, diffuseState );
|
||||
mShadowManager->setLightShadowMap(lsm);
|
||||
mShadowManager->setLightDynamicShadowMap( dlsm );
|
||||
|
||||
lsm->render(mShadowRPM, diffuseState, false);
|
||||
dlsm->render(mDynamicShadowRPM, diffuseState, true);
|
||||
|
||||
++smUpdatedShadowMaps;
|
||||
}
|
||||
|
||||
// View dependent shadows or ones that are covering the entire
|
||||
// screen are updated every frame no matter the time left in
|
||||
// our shadow rendering budget.
|
||||
if ( lsm->isViewDependent() || lsm->getLastScreenSize() >= 1.0f )
|
||||
if ( dlsm->isViewDependent() || dlsm->getLastScreenSize() >= 1.0f )
|
||||
{
|
||||
++smNearShadowMaps;
|
||||
continue;
|
||||
|
|
@ -224,6 +261,7 @@ void ShadowMapPass::render( SceneManager *sceneManager,
|
|||
// The NULL here is importaint as having it around
|
||||
// will cause extra work in AdvancedLightManager::setLightInfo().
|
||||
mShadowManager->setLightShadowMap( NULL );
|
||||
mShadowManager->setLightDynamicShadowMap( NULL );
|
||||
}
|
||||
|
||||
void ShadowRenderPassManager::addInst( RenderInst *inst )
|
||||
|
|
@ -237,7 +275,29 @@ void ShadowRenderPassManager::addInst( RenderInst *inst )
|
|||
return;
|
||||
|
||||
const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
|
||||
if ( !mat->castsShadows() || mat->isTranslucent() )
|
||||
if ( !mat->castsShadows() || mat->castsDynamicShadows() || mat->isTranslucent() )
|
||||
{
|
||||
// Do not add this instance, return here and avoid the default behavior
|
||||
// of calling up to Parent::addInst()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Parent::addInst(inst);
|
||||
}
|
||||
|
||||
void DynamicShadowRenderPassManager::addInst( RenderInst *inst )
|
||||
{
|
||||
PROFILE_SCOPE(DynamicShadowRenderPassManager_addInst);
|
||||
|
||||
if ( inst->type == RIT_Mesh )
|
||||
{
|
||||
MeshRenderInst *meshRI = static_cast<MeshRenderInst*>( inst );
|
||||
if ( !meshRI->matInst )
|
||||
return;
|
||||
|
||||
const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
|
||||
if ( !mat->castsShadows() || !mat->castsDynamicShadows() || mat->isTranslucent() )
|
||||
{
|
||||
// Do not add this instance, return here and avoid the default behavior
|
||||
// of calling up to Parent::addInst()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue