mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-09 15:30:41 +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
|
|
@ -60,6 +60,8 @@ LightBase::LightBase()
|
|||
mColor( ColorF::WHITE ),
|
||||
mBrightness( 1.0f ),
|
||||
mCastShadows( false ),
|
||||
mStaticRefreshFreq( 250 ),
|
||||
mDynamicRefreshFreq( 8 ),
|
||||
mPriority( 1.0f ),
|
||||
mAnimationData( NULL ),
|
||||
mFlareData( NULL ),
|
||||
|
|
@ -90,6 +92,8 @@ void LightBase::initPersistFields()
|
|||
addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
|
||||
addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );
|
||||
addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
|
||||
addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
|
||||
addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)" );
|
||||
addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
|
||||
"Priority determines if a light has a stronger effect than, those with a lower value" );
|
||||
|
||||
|
|
@ -277,6 +281,8 @@ U32 LightBase::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
|
|||
stream->write( mBrightness );
|
||||
|
||||
stream->writeFlag( mCastShadows );
|
||||
stream->write(mStaticRefreshFreq);
|
||||
stream->write(mDynamicRefreshFreq);
|
||||
|
||||
stream->write( mPriority );
|
||||
|
||||
|
|
@ -322,6 +328,8 @@ void LightBase::unpackUpdate( NetConnection *conn, BitStream *stream )
|
|||
stream->read( &mColor );
|
||||
stream->read( &mBrightness );
|
||||
mCastShadows = stream->readFlag();
|
||||
stream->read(&mStaticRefreshFreq);
|
||||
stream->read(&mDynamicRefreshFreq);
|
||||
|
||||
stream->read( &mPriority );
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ protected:
|
|||
F32 mBrightness;
|
||||
|
||||
bool mCastShadows;
|
||||
|
||||
S32 mStaticRefreshFreq;
|
||||
S32 mDynamicRefreshFreq;
|
||||
F32 mPriority;
|
||||
|
||||
LightInfo *mLight;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ LightDescription::LightDescription()
|
|||
brightness( 1.0f ),
|
||||
range( 5.0f ),
|
||||
castShadows( false ),
|
||||
mStaticRefreshFreq( 250 ),
|
||||
mDynamicRefreshFreq( 8 ),
|
||||
animationData( NULL ),
|
||||
animationDataId( 0 ),
|
||||
animationPeriod( 1.0f ),
|
||||
|
|
@ -94,6 +96,8 @@ void LightDescription::initPersistFields()
|
|||
addField( "brightness", TypeF32, Offset( brightness, LightDescription ), "Adjusts the lights power, 0 being off completely." );
|
||||
addField( "range", TypeF32, Offset( range, LightDescription ), "Controls the size (radius) of the light" );
|
||||
addField( "castShadows", TypeBool, Offset( castShadows, LightDescription ), "Enables/disabled shadow casts by this light." );
|
||||
addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightDescription ), "static shadow refresh rate (milliseconds)" );
|
||||
addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightDescription ), "dynamic shadow refresh rate (milliseconds)" );
|
||||
|
||||
endGroup( "Light" );
|
||||
|
||||
|
|
@ -153,6 +157,8 @@ void LightDescription::packData( BitStream *stream )
|
|||
stream->write( brightness );
|
||||
stream->write( range );
|
||||
stream->writeFlag( castShadows );
|
||||
stream->write(mStaticRefreshFreq);
|
||||
stream->write(mDynamicRefreshFreq);
|
||||
|
||||
stream->write( animationPeriod );
|
||||
stream->write( animationPhase );
|
||||
|
|
@ -181,6 +187,8 @@ void LightDescription::unpackData( BitStream *stream )
|
|||
stream->read( &brightness );
|
||||
stream->read( &range );
|
||||
castShadows = stream->readFlag();
|
||||
stream->read(&mStaticRefreshFreq);
|
||||
stream->read(&mDynamicRefreshFreq);
|
||||
|
||||
stream->read( &animationPeriod );
|
||||
stream->read( &animationPhase );
|
||||
|
|
@ -200,6 +208,8 @@ void LightDescription::submitLight( LightState *state, const MatrixF &xfm, Light
|
|||
li->setRange( range );
|
||||
li->setColor( color );
|
||||
li->setCastShadows( castShadows );
|
||||
li->setStaticRefreshFreq(mStaticRefreshFreq);
|
||||
li->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
||||
li->setTransform( xfm );
|
||||
|
||||
if ( animationData )
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ public:
|
|||
F32 brightness;
|
||||
F32 range;
|
||||
bool castShadows;
|
||||
S32 mStaticRefreshFreq;
|
||||
S32 mDynamicRefreshFreq;
|
||||
|
||||
LightAnimData *animationData;
|
||||
S32 animationDataId;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ void PointLight::_conformLights()
|
|||
|
||||
mLight->setBrightness( mBrightness );
|
||||
mLight->setCastShadows( mCastShadows );
|
||||
mLight->setStaticRefreshFreq(mStaticRefreshFreq);
|
||||
mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
||||
mLight->setPriority( mPriority );
|
||||
|
||||
// Update the bounds and scale to fit our light.
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ void SpotLight::_conformLights()
|
|||
mLight->setColor( mColor );
|
||||
mLight->setBrightness( mBrightness );
|
||||
mLight->setCastShadows( mCastShadows );
|
||||
mLight->setStaticRefreshFreq(mStaticRefreshFreq);
|
||||
mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
||||
mLight->setPriority( mPriority );
|
||||
|
||||
mOuterConeAngle = getMax( 0.01f, mOuterConeAngle );
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ ScatterSky::ScatterSky()
|
|||
mBrightness = 1.0f;
|
||||
|
||||
mCastShadows = true;
|
||||
mStaticRefreshFreq = 8;
|
||||
mDynamicRefreshFreq = 8;
|
||||
mDirty = true;
|
||||
|
||||
mLight = LightManager::createLightInfo();
|
||||
|
|
@ -271,6 +273,8 @@ void ScatterSky::_conformLights()
|
|||
mLight->setAmbient( mAmbientColor );
|
||||
mLight->setColor( mSunColor );
|
||||
mLight->setCastShadows( mCastShadows );
|
||||
mLight->setStaticRefreshFreq(mStaticRefreshFreq);
|
||||
mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
||||
|
||||
FogData fog = getSceneManager()->getFogData();
|
||||
fog.color = mFogColor;
|
||||
|
|
@ -381,6 +385,9 @@ void ScatterSky::initPersistFields()
|
|||
addField( "castShadows", TypeBool, Offset( mCastShadows, ScatterSky ),
|
||||
"Enables/disables shadows cast by objects due to ScatterSky light." );
|
||||
|
||||
addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, ScatterSky), "static shadow refresh rate (milliseconds)");
|
||||
addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, ScatterSky), "dynamic shadow refresh rate (milliseconds)");
|
||||
|
||||
addField( "brightness", TypeF32, Offset( mBrightness, ScatterSky ),
|
||||
"The brightness of the ScatterSky's light object." );
|
||||
|
||||
|
|
@ -487,6 +494,8 @@ U32 ScatterSky::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
|||
stream->write( mBrightness );
|
||||
|
||||
stream->writeFlag( mCastShadows );
|
||||
stream->write(mStaticRefreshFreq);
|
||||
stream->write(mDynamicRefreshFreq);
|
||||
|
||||
stream->write( mFlareScale );
|
||||
|
||||
|
|
@ -588,6 +597,8 @@ void ScatterSky::unpackUpdate(NetConnection *con, BitStream *stream)
|
|||
stream->read( &mBrightness );
|
||||
|
||||
mCastShadows = stream->readFlag();
|
||||
stream->read(&mStaticRefreshFreq);
|
||||
stream->read(&mDynamicRefreshFreq);
|
||||
|
||||
stream->read( &mFlareScale );
|
||||
|
||||
|
|
|
|||
|
|
@ -207,6 +207,8 @@ protected:
|
|||
LightInfo *mLight;
|
||||
|
||||
bool mCastShadows;
|
||||
S32 mStaticRefreshFreq;
|
||||
S32 mDynamicRefreshFreq;
|
||||
bool mDirty;
|
||||
|
||||
LightFlareData *mFlareData;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ Sun::Sun()
|
|||
mSunAzimuth = 0.0f;
|
||||
mSunElevation = 35.0f;
|
||||
mCastShadows = true;
|
||||
mStaticRefreshFreq = 250;
|
||||
mDynamicRefreshFreq = 8;
|
||||
|
||||
mAnimateSun = false;
|
||||
mTotalTime = 0.0f;
|
||||
|
|
@ -163,7 +165,10 @@ void Sun::initPersistFields()
|
|||
"Adjust the Sun's global contrast/intensity");
|
||||
|
||||
addField( "castShadows", TypeBool, Offset( mCastShadows, Sun ),
|
||||
"Enables/disables shadows cast by objects due to Sun light");
|
||||
"Enables/disables shadows cast by objects due to Sun light");
|
||||
|
||||
addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, Sun), "static shadow refresh rate (milliseconds)");
|
||||
addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, Sun), "dynamic shadow refresh rate (milliseconds)");
|
||||
|
||||
endGroup( "Lighting" );
|
||||
|
||||
|
|
@ -220,7 +225,9 @@ U32 Sun::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
|
|||
stream->write( mLightColor );
|
||||
stream->write( mLightAmbient );
|
||||
stream->write( mBrightness );
|
||||
stream->writeFlag( mCastShadows );
|
||||
stream->writeFlag( mCastShadows );
|
||||
stream->write(mStaticRefreshFreq);
|
||||
stream->write(mDynamicRefreshFreq);
|
||||
stream->write( mFlareScale );
|
||||
|
||||
if ( stream->writeFlag( mFlareData ) )
|
||||
|
|
@ -254,6 +261,8 @@ void Sun::unpackUpdate( NetConnection *conn, BitStream *stream )
|
|||
stream->read( &mLightAmbient );
|
||||
stream->read( &mBrightness );
|
||||
mCastShadows = stream->readFlag();
|
||||
stream->read(&mStaticRefreshFreq);
|
||||
stream->read(&mDynamicRefreshFreq);
|
||||
stream->read( &mFlareScale );
|
||||
|
||||
if ( stream->readFlag() )
|
||||
|
|
@ -426,6 +435,8 @@ void Sun::_conformLights()
|
|||
// directional color are the same.
|
||||
bool castShadows = mLightColor != mLightAmbient && mCastShadows;
|
||||
mLight->setCastShadows( castShadows );
|
||||
mLight->setStaticRefreshFreq(mStaticRefreshFreq);
|
||||
mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
|
||||
}
|
||||
|
||||
void Sun::_initCorona()
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ protected:
|
|||
F32 mEndElevation;
|
||||
|
||||
bool mCastShadows;
|
||||
S32 mStaticRefreshFreq;
|
||||
S32 mDynamicRefreshFreq;
|
||||
|
||||
LightInfo *mLight;
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,9 @@ S32 ForestCell::renderBatches( SceneRenderState *state, Frustum *culler )
|
|||
if ( culler && culler->isCulled( mBatches[i]->getWorldBox() ) )
|
||||
continue;
|
||||
|
||||
if( state->getCullingState().isOccludedWithExtraPlanesCull( mBatches[i]->getWorldBox() ) )
|
||||
continue;
|
||||
|
||||
mBatches[i]->render( state );
|
||||
renderedItems += mBatches[i]->getItemCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,6 +197,10 @@ void Forest::prepRenderImage( SceneRenderState *state )
|
|||
if ( smDisableImposters )
|
||||
continue;
|
||||
|
||||
// if cell are to far for largest item, then skip out.
|
||||
if( TSShapeInstance::smLastPixelSize < TSShapeInstance::smSmallestVisiblePixelSize )
|
||||
continue;
|
||||
|
||||
PROFILE_SCOPE(Forest_RenderBatches);
|
||||
|
||||
// Keep track of how many cells were batched.
|
||||
|
|
|
|||
|
|
@ -191,10 +191,11 @@ void AdvancedLightBinManager::addLight( LightInfo *light )
|
|||
// Find a shadow map for this light, if it has one
|
||||
ShadowMapParams *lsp = light->getExtended<ShadowMapParams>();
|
||||
LightShadowMap *lsm = lsp->getShadowMap();
|
||||
LightShadowMap *dynamicShadowMap = lsp->getShadowMap(true);
|
||||
|
||||
// Get the right shadow type.
|
||||
ShadowType shadowType = ShadowType_None;
|
||||
if ( light->getCastShadows() &&
|
||||
if ( light->getCastShadows() &&
|
||||
lsm && lsm->hasShadowTex() &&
|
||||
!ShadowMapPass::smDisableShadows )
|
||||
shadowType = lsm->getShadowType();
|
||||
|
|
@ -203,6 +204,7 @@ void AdvancedLightBinManager::addLight( LightInfo *light )
|
|||
LightBinEntry lEntry;
|
||||
lEntry.lightInfo = light;
|
||||
lEntry.shadowMap = lsm;
|
||||
lEntry.dynamicShadowMap = dynamicShadowMap;
|
||||
lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() );
|
||||
|
||||
if( lightType == LightInfo::Spot )
|
||||
|
|
@ -325,10 +327,12 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
|
|||
setupSGData( sgData, state, curLightInfo );
|
||||
curLightMat->setLightParameters( curLightInfo, state, worldToCameraXfm );
|
||||
mShadowManager->setLightShadowMap( curEntry.shadowMap );
|
||||
mShadowManager->setLightDynamicShadowMap( curEntry.dynamicShadowMap );
|
||||
|
||||
// Let the shadow know we're about to render from it.
|
||||
if ( curEntry.shadowMap )
|
||||
curEntry.shadowMap->preLightRender();
|
||||
if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->preLightRender();
|
||||
|
||||
// Set geometry
|
||||
GFX->setVertexBuffer( curEntry.vertBuffer );
|
||||
|
|
@ -351,10 +355,12 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
|
|||
// Tell it we're done rendering.
|
||||
if ( curEntry.shadowMap )
|
||||
curEntry.shadowMap->postLightRender();
|
||||
if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->postLightRender();
|
||||
}
|
||||
|
||||
// Set NULL for active shadow map (so nothing gets confused)
|
||||
mShadowManager->setLightShadowMap(NULL);
|
||||
mShadowManager->setLightDynamicShadowMap(NULL);
|
||||
GFX->setVertexBuffer( NULL );
|
||||
GFX->setPrimitiveBuffer( NULL );
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ protected:
|
|||
{
|
||||
LightInfo* lightInfo;
|
||||
LightShadowMap* shadowMap;
|
||||
LightShadowMap* dynamicShadowMap;
|
||||
LightMaterialInfo* lightMaterial;
|
||||
GFXPrimitiveBuffer* primBuffer;
|
||||
GFXVertexBuffer* vertBuffer;
|
||||
|
|
|
|||
|
|
@ -357,10 +357,13 @@ void AdvancedLightManager::setLightInfo( ProcessedMaterial *pmat,
|
|||
LightingShaderConstants *lsc = getLightingShaderConstants(shaderConsts);
|
||||
|
||||
LightShadowMap *lsm = SHADOWMGR->getCurrentShadowMap();
|
||||
LightShadowMap *dynamicShadowMap = SHADOWMGR->getCurrentDynamicShadowMap();
|
||||
|
||||
LightInfo *light;
|
||||
if ( lsm )
|
||||
if (lsm)
|
||||
light = lsm->getLightInfo();
|
||||
else if ( dynamicShadowMap )
|
||||
light = dynamicShadowMap->getLightInfo();
|
||||
else
|
||||
{
|
||||
light = sgData.lights[0];
|
||||
|
|
@ -385,10 +388,11 @@ void AdvancedLightManager::setLightInfo( ProcessedMaterial *pmat,
|
|||
lsc->mLightInvRadiusSqSC,
|
||||
lsc->mLightSpotDirSC,
|
||||
lsc->mLightSpotAngleSC,
|
||||
lsc->mLightSpotFalloffSC,
|
||||
lsc->mLightSpotFalloffSC,
|
||||
shaderConsts );
|
||||
|
||||
if ( lsm && light->getCastShadows() )
|
||||
// Static
|
||||
if (lsm && light->getCastShadows())
|
||||
{
|
||||
if ( lsc->mWorldToLightProjSC->isValid() )
|
||||
shaderConsts->set( lsc->mWorldToLightProjSC,
|
||||
|
|
@ -426,6 +430,46 @@ void AdvancedLightManager::setLightInfo( ProcessedMaterial *pmat,
|
|||
lsc->mViewToLightProjSC->getType() );
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic
|
||||
if ( dynamicShadowMap )
|
||||
{
|
||||
if ( lsc->mDynamicWorldToLightProjSC->isValid() )
|
||||
shaderConsts->set( lsc->mDynamicWorldToLightProjSC,
|
||||
dynamicShadowMap->getWorldToLightProj(),
|
||||
lsc->mDynamicWorldToLightProjSC->getType() );
|
||||
|
||||
if ( lsc->mDynamicViewToLightProjSC->isValid() )
|
||||
{
|
||||
// TODO: Should probably cache these results and
|
||||
// not do this mul here on every material that needs
|
||||
// this transform.
|
||||
|
||||
shaderConsts->set( lsc->mDynamicViewToLightProjSC,
|
||||
dynamicShadowMap->getWorldToLightProj() * state->getCameraTransform(),
|
||||
lsc->mDynamicViewToLightProjSC->getType() );
|
||||
}
|
||||
|
||||
shaderConsts->setSafe( lsc->mShadowMapSizeSC, 1.0f / (F32)dynamicShadowMap->getTexSize() );
|
||||
|
||||
// Do this last so that overrides can properly override parameters previously set
|
||||
dynamicShadowMap->setShaderParameters(shaderConsts, lsc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( lsc->mDynamicViewToLightProjSC->isValid() )
|
||||
{
|
||||
// TODO: Should probably cache these results and
|
||||
// not do this mul here on every material that needs
|
||||
// this transform.
|
||||
MatrixF proj;
|
||||
light->getWorldToLightProj( &proj );
|
||||
|
||||
shaderConsts->set( lsc->mDynamicViewToLightProjSC,
|
||||
proj * state->getCameraTransform(),
|
||||
lsc->mDynamicViewToLightProjSC->getType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdvancedLightManager::registerGlobalLight(LightInfo *light, SimObject *obj)
|
||||
|
|
@ -454,22 +498,34 @@ bool AdvancedLightManager::setTextureStage( const SceneData &sgData,
|
|||
ShaderConstHandles *handles )
|
||||
{
|
||||
LightShadowMap* lsm = SHADOWMGR->getCurrentShadowMap();
|
||||
LightShadowMap* dynamicShadowMap = SHADOWMGR->getCurrentDynamicShadowMap();
|
||||
|
||||
// Assign Shadowmap, if it exists
|
||||
LightingShaderConstants* lsc = getLightingShaderConstants(shaderConsts);
|
||||
if ( !lsc )
|
||||
return false;
|
||||
|
||||
if ( lsm && lsm->getLightInfo()->getCastShadows() )
|
||||
return lsm->setTextureStage( currTexFlag, lsc );
|
||||
|
||||
|
||||
if ( currTexFlag == Material::DynamicLight )
|
||||
{
|
||||
// Static
|
||||
if ( lsm && lsm->getLightInfo()->getCastShadows() )
|
||||
return lsm->setTextureStage( currTexFlag, lsc );
|
||||
|
||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, GFXTexHandle::ONE );
|
||||
|
||||
return true;
|
||||
} else if ( currTexFlag == Material::DynamicShadowMap )
|
||||
{
|
||||
// Dynamic
|
||||
if ( dynamicShadowMap )
|
||||
return dynamicShadowMap->setTextureStage( currTexFlag, lsc );
|
||||
|
||||
S32 reg = lsc->mDynamicShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, GFXTexHandle::ONE );
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( currTexFlag == Material::DynamicLightMask )
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ LightInfo::LightInfo()
|
|||
mOuterConeAngle( 90.0f ),
|
||||
mType( Vector ),
|
||||
mCastShadows( false ),
|
||||
mStaticRefreshFreq( 250 ),
|
||||
mDynamicRefreshFreq( 8 ),
|
||||
mPriority( 1.0f ),
|
||||
mScore( 0.0f ),
|
||||
mDebugRender( false )
|
||||
|
|
@ -72,6 +74,8 @@ void LightInfo::set( const LightInfo *light )
|
|||
mOuterConeAngle = light->mOuterConeAngle;
|
||||
mType = light->mType;
|
||||
mCastShadows = light->mCastShadows;
|
||||
mStaticRefreshFreq = light->mStaticRefreshFreq;
|
||||
mDynamicRefreshFreq = light->mDynamicRefreshFreq;
|
||||
|
||||
for ( U32 i=0; i < mExtended.size(); i++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -131,6 +131,9 @@ protected:
|
|||
|
||||
bool mCastShadows;
|
||||
|
||||
S32 mStaticRefreshFreq;
|
||||
S32 mDynamicRefreshFreq;
|
||||
|
||||
::Vector<LightInfoEx*> mExtended;
|
||||
|
||||
/// The priority of this light used for
|
||||
|
|
@ -190,6 +193,12 @@ public:
|
|||
|
||||
bool getCastShadows() const { return mCastShadows; }
|
||||
void setCastShadows( bool castShadows ) { mCastShadows = castShadows; }
|
||||
|
||||
S32 getStaticRefreshFreq() const { return mStaticRefreshFreq; }
|
||||
void setStaticRefreshFreq(S32 _staticRefreshFreq) { mStaticRefreshFreq = _staticRefreshFreq; }
|
||||
|
||||
S32 getDynamicRefreshFreq() const { return mDynamicRefreshFreq; }
|
||||
void setDynamicRefreshFreq(S32 _dynamicRefreshFreq) { mDynamicRefreshFreq = _dynamicRefreshFreq; }
|
||||
|
||||
void setPriority( F32 priority ) { mPriority = priority; }
|
||||
F32 getPriority() const { return mPriority; }
|
||||
|
|
|
|||
|
|
@ -92,14 +92,17 @@ LightShadowMap::LightShadowMap( LightInfo *light )
|
|||
mVizQuery( NULL ),
|
||||
mWasOccluded( false ),
|
||||
mLastScreenSize( 0.0f ),
|
||||
mLastPriority( 0.0f )
|
||||
mLastPriority( 0.0f ),
|
||||
mIsDynamic( false )
|
||||
{
|
||||
GFXTextureManager::addEventDelegate( this, &LightShadowMap::_onTextureEvent );
|
||||
|
||||
mTarget = GFX->allocRenderToTextureTarget();
|
||||
mVizQuery = GFX->createOcclusionQuery();
|
||||
|
||||
smShadowMaps.push_back( this );
|
||||
smShadowMaps.push_back(this);
|
||||
mStaticRefreshTimer = PlatformTimer::create();
|
||||
mDynamicRefreshTimer = PlatformTimer::create();
|
||||
}
|
||||
|
||||
LightShadowMap::~LightShadowMap()
|
||||
|
|
@ -268,11 +271,20 @@ GFXTextureObject* LightShadowMap::_getDepthTarget( U32 width, U32 height )
|
|||
|
||||
bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc )
|
||||
{
|
||||
if ( currTexFlag == Material::DynamicLight )
|
||||
if ( currTexFlag == Material::DynamicLight && !isDynamic() )
|
||||
{
|
||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, mShadowMapTex);
|
||||
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, mShadowMapTex);
|
||||
|
||||
return true;
|
||||
} else if ( currTexFlag == Material::DynamicShadowMap && isDynamic() )
|
||||
{
|
||||
S32 reg = lsc->mDynamicShadowMapSC->getSamplerRegister();
|
||||
|
||||
if ( reg != -1 )
|
||||
GFX->setTexture( reg, mShadowMapTex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -296,8 +308,18 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants*
|
|||
}
|
||||
|
||||
void LightShadowMap::render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
const SceneRenderState *diffuseState,
|
||||
bool _dynamic)
|
||||
{
|
||||
// control how often shadow maps are refreshed
|
||||
if (!_dynamic && (mStaticRefreshTimer->getElapsedMs() < getLightInfo()->getStaticRefreshFreq()))
|
||||
return;
|
||||
mStaticRefreshTimer->reset();
|
||||
|
||||
if (_dynamic && (mDynamicRefreshTimer->getElapsedMs() < getLightInfo()->getDynamicRefreshFreq()))
|
||||
return;
|
||||
mDynamicRefreshTimer->reset();
|
||||
|
||||
mDebugTarget.setTexture( NULL );
|
||||
_render( renderPass, diffuseState );
|
||||
mDebugTarget.setTexture( mShadowMapTex );
|
||||
|
|
@ -456,25 +478,35 @@ LightingShaderConstants::LightingShaderConstants()
|
|||
mLightInvRadiusSqSC(NULL),
|
||||
mLightSpotDirSC(NULL),
|
||||
mLightSpotAngleSC(NULL),
|
||||
mLightSpotFalloffSC(NULL),
|
||||
mLightSpotFalloffSC(NULL),
|
||||
mShadowMapSC(NULL),
|
||||
mDynamicShadowMapSC(NULL),
|
||||
mShadowMapSizeSC(NULL),
|
||||
mCookieMapSC(NULL),
|
||||
mRandomDirsConst(NULL),
|
||||
mShadowSoftnessConst(NULL),
|
||||
mAtlasXOffsetSC(NULL),
|
||||
mAtlasYOffsetSC(NULL),
|
||||
mAtlasScaleSC(NULL),
|
||||
mFadeStartLength(NULL),
|
||||
mOverDarkFactorPSSM(NULL),
|
||||
mTapRotationTexSC(NULL),
|
||||
|
||||
mWorldToLightProjSC(NULL),
|
||||
mViewToLightProjSC(NULL),
|
||||
mScaleXSC(NULL),
|
||||
mScaleYSC(NULL),
|
||||
mOffsetXSC(NULL),
|
||||
mOffsetYSC(NULL),
|
||||
mAtlasXOffsetSC(NULL),
|
||||
mAtlasYOffsetSC(NULL),
|
||||
mAtlasScaleSC(NULL),
|
||||
mFadeStartLength(NULL),
|
||||
mFarPlaneScalePSSM(NULL),
|
||||
mOverDarkFactorPSSM(NULL),
|
||||
mTapRotationTexSC(NULL)
|
||||
|
||||
mDynamicWorldToLightProjSC(NULL),
|
||||
mDynamicViewToLightProjSC(NULL),
|
||||
mDynamicScaleXSC(NULL),
|
||||
mDynamicScaleYSC(NULL),
|
||||
mDynamicOffsetXSC(NULL),
|
||||
mDynamicOffsetYSC(NULL),
|
||||
mDynamicFarPlaneScalePSSM(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -513,29 +545,35 @@ void LightingShaderConstants::init(GFXShader* shader)
|
|||
mLightSpotFalloffSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotFalloff );
|
||||
|
||||
mShadowMapSC = shader->getShaderConstHandle("$shadowMap");
|
||||
mDynamicShadowMapSC = shader->getShaderConstHandle("$dynamicShadowMap");
|
||||
mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize");
|
||||
|
||||
mCookieMapSC = shader->getShaderConstHandle("$cookieMap");
|
||||
|
||||
mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness");
|
||||
|
||||
mWorldToLightProjSC = shader->getShaderConstHandle("$worldToLightProj");
|
||||
mViewToLightProjSC = shader->getShaderConstHandle("$viewToLightProj");
|
||||
|
||||
mScaleXSC = shader->getShaderConstHandle("$scaleX");
|
||||
mScaleYSC = shader->getShaderConstHandle("$scaleY");
|
||||
mOffsetXSC = shader->getShaderConstHandle("$offsetX");
|
||||
mOffsetYSC = shader->getShaderConstHandle("$offsetY");
|
||||
mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset");
|
||||
mAtlasYOffsetSC = shader->getShaderConstHandle("$atlasYOffset");
|
||||
mAtlasScaleSC = shader->getShaderConstHandle("$atlasScale");
|
||||
|
||||
mFadeStartLength = shader->getShaderConstHandle("$fadeStartLength");
|
||||
mOverDarkFactorPSSM = shader->getShaderConstHandle("$overDarkPSSM");
|
||||
mTapRotationTexSC = shader->getShaderConstHandle( "$gTapRotationTex" );
|
||||
|
||||
mWorldToLightProjSC = shader->getShaderConstHandle("$worldToLightProj");
|
||||
mViewToLightProjSC = shader->getShaderConstHandle("$viewToLightProj");
|
||||
mScaleXSC = shader->getShaderConstHandle("$scaleX");
|
||||
mScaleYSC = shader->getShaderConstHandle("$scaleY");
|
||||
mOffsetXSC = shader->getShaderConstHandle("$offsetX");
|
||||
mOffsetYSC = shader->getShaderConstHandle("$offsetY");
|
||||
mFarPlaneScalePSSM = shader->getShaderConstHandle("$farPlaneScalePSSM");
|
||||
|
||||
mOverDarkFactorPSSM = shader->getShaderConstHandle("$overDarkPSSM");
|
||||
|
||||
mTapRotationTexSC = shader->getShaderConstHandle( "$gTapRotationTex" );
|
||||
mDynamicWorldToLightProjSC = shader->getShaderConstHandle("$dynamicWorldToLightProj");
|
||||
mDynamicViewToLightProjSC = shader->getShaderConstHandle("$dynamicViewToLightProj");
|
||||
mDynamicScaleXSC = shader->getShaderConstHandle("$dynamicScaleX");
|
||||
mDynamicScaleYSC = shader->getShaderConstHandle("$dynamicScaleY");
|
||||
mDynamicOffsetXSC = shader->getShaderConstHandle("$dynamicOffsetX");
|
||||
mDynamicOffsetYSC = shader->getShaderConstHandle("$dynamicOffsetY");
|
||||
mDynamicFarPlaneScalePSSM = shader->getShaderConstHandle("$dynamicFarPlaneScalePSSM");
|
||||
|
||||
mInit = true;
|
||||
}
|
||||
|
|
@ -558,7 +596,9 @@ LightInfoExType ShadowMapParams::Type( "" );
|
|||
|
||||
ShadowMapParams::ShadowMapParams( LightInfo *light )
|
||||
: mLight( light ),
|
||||
mShadowMap( NULL )
|
||||
mShadowMap( NULL ),
|
||||
mDynamicShadowMap ( NULL ),
|
||||
isDynamic ( true )
|
||||
{
|
||||
attenuationRatio.set( 0.0f, 1.0f, 1.0f );
|
||||
shadowType = ShadowType_Spot;
|
||||
|
|
@ -576,6 +616,7 @@ ShadowMapParams::ShadowMapParams( LightInfo *light )
|
|||
ShadowMapParams::~ShadowMapParams()
|
||||
{
|
||||
SAFE_DELETE( mShadowMap );
|
||||
SAFE_DELETE( mDynamicShadowMap );
|
||||
}
|
||||
|
||||
void ShadowMapParams::_validate()
|
||||
|
|
@ -632,39 +673,55 @@ void ShadowMapParams::_validate()
|
|||
texSize = mClamp( texSize, 32, maxTexSize );
|
||||
}
|
||||
|
||||
LightShadowMap* ShadowMapParams::getOrCreateShadowMap()
|
||||
LightShadowMap* ShadowMapParams::getOrCreateShadowMap(bool _isDynamic)
|
||||
{
|
||||
if ( mShadowMap )
|
||||
if (_isDynamic && mDynamicShadowMap)
|
||||
return mDynamicShadowMap;
|
||||
|
||||
if (!_isDynamic && mShadowMap)
|
||||
return mShadowMap;
|
||||
|
||||
if ( !mLight->getCastShadows() )
|
||||
return NULL;
|
||||
|
||||
LightShadowMap* newShadowMap = NULL;
|
||||
|
||||
switch ( mLight->getType() )
|
||||
{
|
||||
case LightInfo::Spot:
|
||||
mShadowMap = new SingleLightShadowMap( mLight );
|
||||
newShadowMap = new SingleLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
case LightInfo::Vector:
|
||||
mShadowMap = new PSSMLightShadowMap( mLight );
|
||||
newShadowMap = new PSSMLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
case LightInfo::Point:
|
||||
|
||||
if ( shadowType == ShadowType_CubeMap )
|
||||
mShadowMap = new CubeLightShadowMap( mLight );
|
||||
newShadowMap = new CubeLightShadowMap( mLight );
|
||||
else if ( shadowType == ShadowType_Paraboloid )
|
||||
mShadowMap = new ParaboloidLightShadowMap( mLight );
|
||||
newShadowMap = new ParaboloidLightShadowMap( mLight );
|
||||
else
|
||||
mShadowMap = new DualParaboloidLightShadowMap( mLight );
|
||||
newShadowMap = new DualParaboloidLightShadowMap( mLight );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return mShadowMap;
|
||||
if ( _isDynamic )
|
||||
{
|
||||
newShadowMap->setDynamic( true );
|
||||
mDynamicShadowMap = newShadowMap;
|
||||
return mDynamicShadowMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
newShadowMap->setDynamic(false);
|
||||
mShadowMap = newShadowMap;
|
||||
return mShadowMap;
|
||||
}
|
||||
}
|
||||
|
||||
GFXTextureObject* ShadowMapParams::getCookieTex()
|
||||
|
|
@ -739,6 +796,7 @@ void ShadowMapParams::unpackUpdate( BitStream *stream )
|
|||
// map so it can be reallocated on the next render.
|
||||
shadowType = newType;
|
||||
SAFE_DELETE( mShadowMap );
|
||||
SAFE_DELETE( mDynamicShadowMap );
|
||||
}
|
||||
|
||||
mathRead( *stream, &attenuationRatio );
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@
|
|||
#ifndef _GFXSHADER_H_
|
||||
#include "gfx/gfxShader.h"
|
||||
#endif
|
||||
#ifndef _PLATFORM_PLATFORMTIMER_H_
|
||||
#include "platform/platformTimer.h"
|
||||
#endif
|
||||
|
||||
class ShadowMapManager;
|
||||
class SceneManager;
|
||||
|
|
@ -88,20 +91,13 @@ struct LightingShaderConstants
|
|||
GFXShaderConstHandle *mLightSpotFalloffSC;
|
||||
|
||||
GFXShaderConstHandle* mShadowMapSC;
|
||||
GFXShaderConstHandle* mDynamicShadowMapSC;
|
||||
GFXShaderConstHandle* mShadowMapSizeSC;
|
||||
|
||||
GFXShaderConstHandle* mCookieMapSC;
|
||||
|
||||
GFXShaderConstHandle* mRandomDirsConst;
|
||||
GFXShaderConstHandle* mShadowSoftnessConst;
|
||||
|
||||
GFXShaderConstHandle* mWorldToLightProjSC;
|
||||
GFXShaderConstHandle* mViewToLightProjSC;
|
||||
|
||||
GFXShaderConstHandle* mScaleXSC;
|
||||
GFXShaderConstHandle* mScaleYSC;
|
||||
GFXShaderConstHandle* mOffsetXSC;
|
||||
GFXShaderConstHandle* mOffsetYSC;
|
||||
GFXShaderConstHandle* mAtlasXOffsetSC;
|
||||
GFXShaderConstHandle* mAtlasYOffsetSC;
|
||||
GFXShaderConstHandle* mAtlasScaleSC;
|
||||
|
|
@ -109,11 +105,28 @@ struct LightingShaderConstants
|
|||
// fadeStartLength.x = Distance in eye space to start fading shadows
|
||||
// fadeStartLength.y = 1 / Length of fade
|
||||
GFXShaderConstHandle* mFadeStartLength;
|
||||
GFXShaderConstHandle* mFarPlaneScalePSSM;
|
||||
GFXShaderConstHandle* mOverDarkFactorPSSM;
|
||||
|
||||
GFXShaderConstHandle* mTapRotationTexSC;
|
||||
|
||||
// Static Specific:
|
||||
GFXShaderConstHandle* mWorldToLightProjSC;
|
||||
GFXShaderConstHandle* mViewToLightProjSC;
|
||||
GFXShaderConstHandle* mScaleXSC;
|
||||
GFXShaderConstHandle* mScaleYSC;
|
||||
GFXShaderConstHandle* mOffsetXSC;
|
||||
GFXShaderConstHandle* mOffsetYSC;
|
||||
GFXShaderConstHandle* mFarPlaneScalePSSM;
|
||||
|
||||
// Dynamic Specific:
|
||||
GFXShaderConstHandle* mDynamicWorldToLightProjSC;
|
||||
GFXShaderConstHandle* mDynamicViewToLightProjSC;
|
||||
GFXShaderConstHandle* mDynamicScaleXSC;
|
||||
GFXShaderConstHandle* mDynamicScaleYSC;
|
||||
GFXShaderConstHandle* mDynamicOffsetXSC;
|
||||
GFXShaderConstHandle* mDynamicOffsetYSC;
|
||||
GFXShaderConstHandle* mDynamicFarPlaneScalePSSM;
|
||||
|
||||
LightingShaderConstants();
|
||||
~LightingShaderConstants();
|
||||
|
||||
|
|
@ -147,7 +160,8 @@ public:
|
|||
virtual ~LightShadowMap();
|
||||
|
||||
void render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState );
|
||||
const SceneRenderState *diffuseState,
|
||||
bool _dynamic);
|
||||
|
||||
U32 getLastUpdate() const { return mLastUpdate; }
|
||||
|
||||
|
|
@ -237,6 +251,8 @@ protected:
|
|||
|
||||
/// The time this shadow was last updated.
|
||||
U32 mLastUpdate;
|
||||
PlatformTimer *mStaticRefreshTimer;
|
||||
PlatformTimer *mDynamicRefreshTimer;
|
||||
|
||||
/// The time this shadow was last culled and prioritized.
|
||||
U32 mLastCull;
|
||||
|
|
@ -274,6 +290,13 @@ protected:
|
|||
/// The callback used to get texture events.
|
||||
/// @see GFXTextureManager::addEventDelegate
|
||||
void _onTextureEvent( GFXTexCallbackCode code );
|
||||
|
||||
bool mIsDynamic;
|
||||
public:
|
||||
|
||||
bool isDynamic() { return mIsDynamic; }
|
||||
void setDynamic(bool value) { mIsDynamic = value; }
|
||||
|
||||
};
|
||||
|
||||
GFX_DeclareTextureProfile( ShadowMapProfile );
|
||||
|
|
@ -296,9 +319,9 @@ public:
|
|||
virtual void packUpdate( BitStream *stream ) const;
|
||||
virtual void unpackUpdate( BitStream *stream );
|
||||
|
||||
LightShadowMap* getShadowMap() const { return mShadowMap; }
|
||||
LightShadowMap* getShadowMap(bool _isDynamic = false) const { return _isDynamic ? mDynamicShadowMap : mShadowMap; }
|
||||
|
||||
LightShadowMap* getOrCreateShadowMap();
|
||||
LightShadowMap* getOrCreateShadowMap(bool _isDynamic = false);
|
||||
|
||||
bool hasCookieTex() const { return cookie.isNotEmpty(); }
|
||||
|
||||
|
|
@ -315,6 +338,7 @@ protected:
|
|||
|
||||
///
|
||||
LightShadowMap *mShadowMap;
|
||||
LightShadowMap *mDynamicShadowMap;
|
||||
|
||||
LightInfo *mLight;
|
||||
|
||||
|
|
@ -376,6 +400,7 @@ public:
|
|||
bool lastSplitTerrainOnly;
|
||||
|
||||
/// @}
|
||||
bool isDynamic;
|
||||
};
|
||||
|
||||
#endif // _LIGHTSHADOWMAP_H_
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "materials/shaderData.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "math/mathUtils.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
|
|
@ -248,6 +249,9 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
TSShapeInstance::smDetailAdjust *= smDetailAdjustScale;
|
||||
TSShapeInstance::smSmallestVisiblePixelSize = smSmallestVisiblePixelSize;
|
||||
|
||||
Vector< Vector<PlaneF> > _extraCull;
|
||||
_calcPlanesCullForShadowCasters( _extraCull, fullFrustum, mLight->getDirection() );
|
||||
|
||||
for (U32 i = 0; i < mNumSplits; i++)
|
||||
{
|
||||
GFXTransformSaver saver;
|
||||
|
|
@ -365,12 +369,17 @@ void PSSMLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
|
||||
shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
|
||||
|
||||
PlaneSetF planeSet( _extraCull[i].address(), _extraCull[i].size() );
|
||||
shadowRenderState.getCullingState().setExtraPlanesCull( planeSet );
|
||||
|
||||
U32 objectMask = SHADOW_TYPEMASK;
|
||||
if ( i == mNumSplits-1 && params->lastSplitTerrainOnly )
|
||||
objectMask = TerrainObjectType;
|
||||
|
||||
sceneManager->renderSceneNoLights( &shadowRenderState, objectMask );
|
||||
|
||||
shadowRenderState.getCullingState().clearExtraPlanesCull();
|
||||
|
||||
_debugRender( &shadowRenderState );
|
||||
}
|
||||
|
||||
|
|
@ -435,18 +444,28 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
|
|||
}
|
||||
}
|
||||
|
||||
params->setSafe(lsc->mScaleXSC, sx);
|
||||
params->setSafe(lsc->mScaleYSC, sy);
|
||||
params->setSafe(lsc->mOffsetXSC, ox);
|
||||
params->setSafe(lsc->mOffsetYSC, oy);
|
||||
// These values change based on static/dynamic.
|
||||
if ( mIsDynamic )
|
||||
{
|
||||
params->setSafe(lsc->mDynamicScaleXSC, sx);
|
||||
params->setSafe(lsc->mDynamicScaleYSC, sy);
|
||||
params->setSafe(lsc->mDynamicOffsetXSC, ox);
|
||||
params->setSafe(lsc->mDynamicOffsetYSC, oy);
|
||||
params->setSafe( lsc->mDynamicFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
} else {
|
||||
params->setSafe(lsc->mScaleXSC, sx);
|
||||
params->setSafe(lsc->mScaleYSC, sy);
|
||||
params->setSafe(lsc->mOffsetXSC, ox);
|
||||
params->setSafe(lsc->mOffsetYSC, oy);
|
||||
params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
}
|
||||
|
||||
params->setSafe(lsc->mAtlasXOffsetSC, aXOff);
|
||||
params->setSafe(lsc->mAtlasYOffsetSC, aYOff);
|
||||
params->setSafe(lsc->mAtlasScaleSC, shadowMapAtlas);
|
||||
|
||||
Point4F lightParams( mLight->getRange().x, p->overDarkFactor.x, 0.0f, 0.0f );
|
||||
params->setSafe( lsc->mLightParamsSC, lightParams );
|
||||
|
||||
params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
|
||||
|
||||
Point2F fadeStartLength(p->fadeStartDist, 0.0f);
|
||||
if (fadeStartLength.x == 0.0f)
|
||||
|
|
@ -462,3 +481,117 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
|
|||
// The softness is a factor of the texel size.
|
||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
|
||||
void PSSMLightShadowMap::_calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir)
|
||||
{
|
||||
|
||||
#define ENABLE_CULL_ASSERT
|
||||
|
||||
PROFILE_SCOPE(PSSMLightShadowMap_render_getCullFrustrum);
|
||||
|
||||
Point3F ligthDir = _ligthDir;
|
||||
PlaneF lightFarPlane, lightNearPlane;
|
||||
MatrixF lightFarPlaneMat(true);
|
||||
MatrixF invLightFarPlaneMat(true);
|
||||
|
||||
// init data
|
||||
{
|
||||
ligthDir.normalize();
|
||||
Point3F viewDir = viewFrustum.getTransform().getForwardVector();
|
||||
viewDir.normalize();
|
||||
const Point3F viewPosition = viewFrustum.getPosition();
|
||||
const F32 viewDistance = viewFrustum.getBounds().len();
|
||||
lightNearPlane = PlaneF(viewPosition + (viewDistance * -ligthDir), ligthDir);
|
||||
|
||||
const Point3F lightFarPlanePos = viewPosition + (viewDistance * ligthDir);
|
||||
lightFarPlane = PlaneF(lightFarPlanePos, -ligthDir);
|
||||
|
||||
lightFarPlaneMat = MathUtils::createOrientFromDir(-ligthDir);
|
||||
lightFarPlaneMat.setPosition(lightFarPlanePos);
|
||||
lightFarPlaneMat.invertTo(&invLightFarPlaneMat);
|
||||
}
|
||||
|
||||
Vector<Point2F> projVertices;
|
||||
|
||||
//project all frustum vertices into plane
|
||||
// all vertices are 2d and local to far plane
|
||||
projVertices.setSize(8);
|
||||
for (int i = 0; i < 8; ++i) //
|
||||
{
|
||||
const Point3F &point = viewFrustum.getPoints()[i];
|
||||
#ifdef ENABLE_CULL_ASSERT
|
||||
AssertFatal( PlaneF::Front == lightNearPlane.whichSide(point), "" );
|
||||
AssertFatal( PlaneF::Front == lightFarPlane.whichSide(point), "" );
|
||||
#endif
|
||||
|
||||
Point3F localPoint(lightFarPlane.project(point));
|
||||
invLightFarPlaneMat.mulP(localPoint);
|
||||
projVertices[i] = Point2F(localPoint.x, localPoint.z);
|
||||
}
|
||||
|
||||
//create hull arround projected proints
|
||||
Vector<Point2F> hullVerts;
|
||||
MathUtils::mBuildHull2D(projVertices, hullVerts);
|
||||
|
||||
Vector<PlaneF> planes;
|
||||
planes.push_back(lightNearPlane);
|
||||
planes.push_back(lightFarPlane);
|
||||
|
||||
//build planes
|
||||
for (int i = 0; i < (hullVerts.size() - 1); ++i)
|
||||
{
|
||||
Point2F pos2D = (hullVerts[i] + hullVerts[i + 1]) / 2;
|
||||
Point3F pos3D(pos2D.x, 0, pos2D.y);
|
||||
|
||||
Point3F pos3DA(hullVerts[i].x, 0, hullVerts[i].y);
|
||||
Point3F pos3DB(hullVerts[i + 1].x, 0, hullVerts[i + 1].y);
|
||||
|
||||
// move hull points to 3d space
|
||||
lightFarPlaneMat.mulP(pos3D);
|
||||
lightFarPlaneMat.mulP(pos3DA);
|
||||
lightFarPlaneMat.mulP(pos3DB);
|
||||
|
||||
PlaneF plane(pos3D, MathUtils::mTriangleNormal(pos3DB, pos3DA, (pos3DA - ligthDir)));
|
||||
planes.push_back(plane);
|
||||
}
|
||||
|
||||
//recalculate planes for each splits
|
||||
for (int split = 0; split < mNumSplits; ++split)
|
||||
{
|
||||
Frustum subFrustum(viewFrustum);
|
||||
subFrustum.cropNearFar(mSplitDist[split], mSplitDist[split + 1]);
|
||||
subFrustum.setFarDist(getMin(subFrustum.getFarDist()*2.5f, viewFrustum.getFarDist()));
|
||||
subFrustum.update();
|
||||
|
||||
Vector<PlaneF> subPlanes = planes;
|
||||
|
||||
for (int planeIdx = 0; planeIdx < subPlanes.size(); ++planeIdx)
|
||||
{
|
||||
PlaneF &plane = subPlanes[planeIdx];
|
||||
F32 minDist = 0;
|
||||
|
||||
//calculate near vertex distance
|
||||
for (int vertexIdx = 0; vertexIdx < 8; ++vertexIdx)
|
||||
{
|
||||
Point3F point = subFrustum.getPoints()[vertexIdx];
|
||||
minDist = getMin(plane.distToPlane(point), minDist);
|
||||
}
|
||||
|
||||
// move plane to near vertex
|
||||
Point3F newPos = plane.getPosition() + (plane.getNormal() * minDist);
|
||||
plane = PlaneF(newPos, plane.getNormal());
|
||||
|
||||
#ifdef ENABLE_CULL_ASSERT
|
||||
for(int x = 0; x < 8; ++x)
|
||||
{
|
||||
AssertFatal( PlaneF::Back != plane.whichSide( subFrustum.getPoints()[x] ), "");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out.push_back(subPlanes);
|
||||
}
|
||||
|
||||
#undef ENABLE_CULL_ASSERT
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ protected:
|
|||
void _setNumSplits( U32 numSplits, U32 texSize );
|
||||
void _calcSplitPos(const Frustum& currFrustum);
|
||||
Box3F _calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist);
|
||||
void _calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir);
|
||||
void _roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum);
|
||||
|
||||
static const S32 MAX_SPLITS = 4;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ Signal<void(void)> ShadowMapManager::smShadowDeactivateSignal;
|
|||
ShadowMapManager::ShadowMapManager()
|
||||
: mShadowMapPass(NULL),
|
||||
mCurrentShadowMap(NULL),
|
||||
mCurrentDynamicShadowMap(NULL),
|
||||
mIsActive(false)
|
||||
{
|
||||
}
|
||||
|
|
@ -98,9 +99,15 @@ void ShadowMapManager::setLightShadowMapForLight( LightInfo *light )
|
|||
{
|
||||
ShadowMapParams *params = light->getExtended<ShadowMapParams>();
|
||||
if ( params )
|
||||
{
|
||||
mCurrentShadowMap = params->getShadowMap();
|
||||
mCurrentDynamicShadowMap = params->getShadowMap(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentShadowMap = NULL;
|
||||
mCurrentDynamicShadowMap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowMapManager::activate()
|
||||
|
|
|
|||
|
|
@ -60,12 +60,14 @@ public:
|
|||
|
||||
/// Sets the current shadowmap (used in setLightInfo/setTextureStage calls)
|
||||
void setLightShadowMap( LightShadowMap *lm ) { mCurrentShadowMap = lm; }
|
||||
void setLightDynamicShadowMap( LightShadowMap *lm ) { mCurrentDynamicShadowMap = lm; }
|
||||
|
||||
/// Looks up the shadow map for the light then sets it.
|
||||
void setLightShadowMapForLight( LightInfo *light );
|
||||
|
||||
/// Return the current shadow map
|
||||
LightShadowMap* getCurrentShadowMap() const { return mCurrentShadowMap; }
|
||||
LightShadowMap* getCurrentDynamicShadowMap() const { return mCurrentDynamicShadowMap; }
|
||||
|
||||
ShadowMapPass* getShadowMapPass() const { return mShadowMapPass; }
|
||||
|
||||
|
|
@ -88,6 +90,7 @@ protected:
|
|||
|
||||
ShadowMapPass *mShadowMapPass;
|
||||
LightShadowMap *mCurrentShadowMap;
|
||||
LightShadowMap *mCurrentDynamicShadowMap;
|
||||
|
||||
///
|
||||
GFXTexHandle mTapRotationTex;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class RenderObjectMgr;
|
|||
class RenderTerrainMgr;
|
||||
class PlatformTimer;
|
||||
class ShadowRenderPassManager;
|
||||
class DynamicShadowRenderPassManager;
|
||||
|
||||
/// ShadowMapPass, this is plugged into the SceneManager to generate
|
||||
/// ShadowMaps for the scene.
|
||||
|
|
@ -83,6 +84,11 @@ public:
|
|||
static bool smDisableShadowsEditor;
|
||||
static bool smDisableShadowsPref;
|
||||
|
||||
/// milliseconds before static redraw
|
||||
static S32 smStaticShadowUpdateFreq;
|
||||
/// milliseconds before dynamic redraw
|
||||
static S32 smDynamicShadowUpdateFreq;
|
||||
|
||||
private:
|
||||
|
||||
static U32 smActiveShadowMaps;
|
||||
|
|
@ -103,6 +109,7 @@ private:
|
|||
LightInfoList mLights;
|
||||
U32 mActiveLights;
|
||||
SimObjectPtr<ShadowRenderPassManager> mShadowRPM;
|
||||
SimObjectPtr<DynamicShadowRenderPassManager> mDynamicShadowRPM;
|
||||
LightManager* mLightManager;
|
||||
ShadowMapManager* mShadowManager;
|
||||
};
|
||||
|
|
@ -117,4 +124,14 @@ public:
|
|||
virtual void addInst( RenderInst *inst );
|
||||
};
|
||||
|
||||
class DynamicShadowRenderPassManager : public RenderPassManager
|
||||
{
|
||||
typedef RenderPassManager Parent;
|
||||
public:
|
||||
DynamicShadowRenderPassManager() : Parent() {}
|
||||
|
||||
/// Add a RenderInstance to the list
|
||||
virtual void addInst(RenderInst *inst);
|
||||
};
|
||||
|
||||
#endif // _SHADOWMAPPASS_H_
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ public:
|
|||
virtual bool isDoubleSided() const = 0;
|
||||
virtual bool isLightmapped() const = 0;
|
||||
virtual bool castsShadows() const = 0;
|
||||
virtual bool castsDynamicShadows() const = 0;
|
||||
};
|
||||
|
||||
#endif // _BASEMATERIALDEFINITION_H_
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ Material::Material()
|
|||
mAlphaRef = 1;
|
||||
|
||||
mCastShadows = true;
|
||||
mCastDynamicShadows = true;
|
||||
|
||||
mPlanarReflection = false;
|
||||
|
||||
|
|
@ -288,7 +289,7 @@ void Material::initPersistFields()
|
|||
|
||||
addField( "useAnisotropic", TypeBool, Offset(mUseAnisotropic, Material), MAX_STAGES,
|
||||
"Use anisotropic filtering for the textures of this stage." );
|
||||
|
||||
|
||||
addField("envMap", TypeImageFilename, Offset(mEnvMapFilename, Material), MAX_STAGES,
|
||||
"The name of an environment map cube map to apply to this material." );
|
||||
|
||||
|
|
@ -390,6 +391,9 @@ void Material::initPersistFields()
|
|||
addField( "castShadows", TypeBool, Offset(mCastShadows, Material),
|
||||
"If set to false the lighting system will not cast shadows from this material." );
|
||||
|
||||
addField( "castDynamicShadows", TypeBool, Offset(mCastDynamicShadows, Material),
|
||||
"If set to false the lighting system will not cast dynamic shadows from this material." );
|
||||
|
||||
addField("planarReflection", TypeBool, Offset(mPlanarReflection, Material), "@internal" );
|
||||
|
||||
addField("translucent", TypeBool, Offset(mTranslucent, Material),
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ public:
|
|||
NormalizeCube,
|
||||
TexTarget,
|
||||
AccuMap,
|
||||
DynamicShadowMap,
|
||||
};
|
||||
|
||||
enum BlendOp
|
||||
|
|
@ -219,7 +220,7 @@ public:
|
|||
|
||||
/// The strength scalar for the detail normal map.
|
||||
F32 mDetailNormalMapStrength[MAX_STAGES];
|
||||
|
||||
|
||||
FileName mEnvMapFilename[MAX_STAGES];
|
||||
|
||||
/// This color is the diffuse color of the material
|
||||
|
|
@ -299,6 +300,7 @@ public:
|
|||
/// A generic setting which tells the system to skip
|
||||
/// generation of shadows from this material.
|
||||
bool mCastShadows;
|
||||
bool mCastDynamicShadows;
|
||||
|
||||
bool mAlphaTest;
|
||||
U32 mAlphaRef;
|
||||
|
|
@ -355,6 +357,7 @@ public:
|
|||
virtual void setAutoGenerated(bool isAutoGenerated) { mAutoGenerated = isAutoGenerated; }
|
||||
virtual bool isLightmapped() const;
|
||||
virtual bool castsShadows() const { return mCastShadows; }
|
||||
virtual bool castsDynamicShadows() const { return mCastDynamicShadows; }
|
||||
const String &getPath() const { return mPath; }
|
||||
|
||||
void flush();
|
||||
|
|
|
|||
|
|
@ -85,6 +85,14 @@ void ProcessedCustomMaterial::_setStageData()
|
|||
continue;
|
||||
}
|
||||
|
||||
if(filename.equal(String("$dynamicShadowMap"), String::NoCase))
|
||||
{
|
||||
rpd->mTexType[i] = Material::DynamicShadowMap;
|
||||
rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
|
||||
mMaxTex = i+1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(filename.equal(String("$dynamiclightmask"), String::NoCase))
|
||||
{
|
||||
rpd->mTexType[i] = Material::DynamicLightMask;
|
||||
|
|
|
|||
|
|
@ -908,6 +908,14 @@ inline bool mIsNaN( const Point2F &p )
|
|||
return mIsNaN_F( p.x ) || mIsNaN_F( p.y );
|
||||
}
|
||||
|
||||
/// Return 0 if points are colinear
|
||||
/// Return positive if p0p1p2 are counter-clockwise
|
||||
/// Return negative if p0p1p2 are clockwise
|
||||
inline F64 mCross(const Point2F &p0, const Point2F &p1, const Point2F &pt2)
|
||||
{
|
||||
return (p1.x - p0.x) * (pt2.y - p0.y) - (p1.y - p0.y) * (pt2.x - p0.x);
|
||||
}
|
||||
|
||||
|
||||
namespace DictHash
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1845,4 +1845,55 @@ U32 extrudePolygonEdgesFromPoint( const Point3F* vertices, U32 numVertices, cons
|
|||
return numPlanes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MathUtils::mBuildHull2D(const Vector<Point2F> _inPoints, Vector<Point2F> &hullPoints)
|
||||
{
|
||||
/// Andrew's monotone chain convex hull algorithm implementation
|
||||
|
||||
struct Util
|
||||
{
|
||||
//compare by x and then by y
|
||||
static int CompareLexicographic( const Point2F *a, const Point2F *b)
|
||||
{
|
||||
return a->x < b->x || (a->x == b->x && a->y < b->y);
|
||||
}
|
||||
};
|
||||
|
||||
hullPoints.clear();
|
||||
hullPoints.setSize( _inPoints.size()*2 );
|
||||
|
||||
// sort in points by x and then by y
|
||||
Vector<Point2F> inSortedPoints = _inPoints;
|
||||
inSortedPoints.sort( &Util::CompareLexicographic );
|
||||
|
||||
Point2F* lowerHullPtr = hullPoints.address();
|
||||
U32 lowerHullIdx = 0;
|
||||
|
||||
//lower part of hull
|
||||
for( int i = 0; i < inSortedPoints.size(); ++i )
|
||||
{
|
||||
while( lowerHullIdx >= 2 && mCross( lowerHullPtr[ lowerHullIdx - 2], lowerHullPtr[lowerHullIdx - 1], inSortedPoints[i] ) <= 0 )
|
||||
--lowerHullIdx;
|
||||
|
||||
lowerHullPtr[lowerHullIdx++] = inSortedPoints[i];
|
||||
}
|
||||
|
||||
--lowerHullIdx; // last point are the same as first in upperHullPtr
|
||||
|
||||
Point2F* upperHullPtr = hullPoints.address() + lowerHullIdx;
|
||||
U32 upperHullIdx = 0;
|
||||
|
||||
//upper part of hull
|
||||
for( int i = inSortedPoints.size()-1; i >= 0; --i )
|
||||
{
|
||||
while( upperHullIdx >= 2 && mCross( upperHullPtr[ upperHullIdx - 2], upperHullPtr[upperHullIdx - 1], inSortedPoints[i] ) <= 0 )
|
||||
--upperHullIdx;
|
||||
|
||||
upperHullPtr[upperHullIdx++] = inSortedPoints[i];
|
||||
}
|
||||
|
||||
hullPoints.setSize( lowerHullIdx + upperHullIdx );
|
||||
}
|
||||
|
||||
} // namespace MathUtils
|
||||
|
|
|
|||
|
|
@ -417,6 +417,9 @@ namespace MathUtils
|
|||
|
||||
//void findFarthestPoint( const Point3F* points, U32 numPoints, const Point3F& fromPoint, )
|
||||
|
||||
/// Build a convex hull from a cloud of 2D points, first and last hull point are the same.
|
||||
void mBuildHull2D(const Vector<Point2F> inPoints, Vector<Point2F> &hullPoints);
|
||||
|
||||
} // namespace MathUtils
|
||||
|
||||
#endif // _MATHUTILS_H_
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ SceneCullingState::SceneCullingState( SceneManager* sceneManager, const SceneCam
|
|||
SceneCullingVolume::Includer,
|
||||
PlaneSetF( planes, 4 )
|
||||
);
|
||||
|
||||
clearExtraPlanesCull();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -789,6 +791,9 @@ U32 SceneCullingState::cullObjects( SceneObject** objects, U32 numObjects, U32 c
|
|||
result == SceneZoneCullingState::CullingTestPositiveByOcclusion );
|
||||
}
|
||||
|
||||
if( !isCulled )
|
||||
isCulled = isOccludedWithExtraPlanesCull( object->getWorldBox() );
|
||||
|
||||
if( !isCulled )
|
||||
objects[ numRemainingObjects ++ ] = object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ class SceneCullingState
|
|||
/// The root culling frustum, which may be different from the camera frustum
|
||||
Frustum mCullingFrustum;
|
||||
|
||||
/// Extra planes for culling.
|
||||
PlaneSetF mExtraPlanesCull;
|
||||
|
||||
/// Occluders that have been added to this render state. Adding an occluder does not
|
||||
/// necessarily result in an occluder volume being added. To not repeatedly try to
|
||||
/// process the same occluder object, all objects that are added are recorded here.
|
||||
|
|
@ -301,6 +304,21 @@ class SceneCullingState
|
|||
/// (or, if no zone is selected, all volumes in the outdoor zone) to the debug drawer.
|
||||
void debugRenderCullingVolumes() const;
|
||||
|
||||
/// Set planes for extra culling
|
||||
void setExtraPlanesCull( const PlaneSetF &cull) { mExtraPlanesCull = cull; }
|
||||
|
||||
/// Clear planes for extra culling.
|
||||
void clearExtraPlanesCull() { mExtraPlanesCull = PlaneSetF(NULL, 0); }
|
||||
|
||||
/// Check extra planes culling
|
||||
bool isOccludedWithExtraPlanesCull(const Box3F &box) const
|
||||
{
|
||||
if(mExtraPlanesCull.getNumPlanes())
|
||||
return mExtraPlanesCull.testPotentialIntersection( box ) == GeometryOutside;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef SceneZoneCullingState::CullingTestResult CullingTestResult;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue