Merge pull request #1442 from Azaezel/shadow_caching

This all seems to work pretty well.
This commit is contained in:
Areloch 2015-11-12 12:49:58 -06:00
commit 92aa785bb2
61 changed files with 1490 additions and 466 deletions

View file

@ -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 );

View file

@ -56,7 +56,8 @@ protected:
F32 mBrightness;
bool mCastShadows;
S32 mStaticRefreshFreq;
S32 mDynamicRefreshFreq;
F32 mPriority;
LightInfo *mLight;

View file

@ -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 )

View file

@ -101,6 +101,8 @@ public:
F32 brightness;
F32 range;
bool castShadows;
S32 mStaticRefreshFreq;
S32 mDynamicRefreshFreq;
LightAnimData *animationData;
S32 animationDataId;

View file

@ -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.

View file

@ -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 );

View file

@ -144,6 +144,8 @@ ScatterSky::ScatterSky()
mBrightness = 1.0f;
mCastShadows = true;
mStaticRefreshFreq = 8;
mDynamicRefreshFreq = 8;
mDirty = true;
mLight = LightManager::createLightInfo();
@ -264,6 +266,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;
@ -374,6 +378,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." );
@ -480,6 +487,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 );
@ -581,6 +590,8 @@ void ScatterSky::unpackUpdate(NetConnection *con, BitStream *stream)
stream->read( &mBrightness );
mCastShadows = stream->readFlag();
stream->read(&mStaticRefreshFreq);
stream->read(&mDynamicRefreshFreq);
stream->read( &mFlareScale );

View file

@ -199,6 +199,8 @@ protected:
LightInfo *mLight;
bool mCastShadows;
S32 mStaticRefreshFreq;
S32 mDynamicRefreshFreq;
bool mDirty;
LightFlareData *mFlareData;

View file

@ -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()

View file

@ -65,6 +65,8 @@ protected:
F32 mEndElevation;
bool mCastShadows;
S32 mStaticRefreshFreq;
S32 mDynamicRefreshFreq;
LightInfo *mLight;

View file

@ -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();
}

View file

@ -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.

View file

@ -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 );

View file

@ -185,6 +185,7 @@ protected:
{
LightInfo* lightInfo;
LightShadowMap* shadowMap;
LightShadowMap* dynamicShadowMap;
LightMaterialInfo* lightMaterial;
GFXPrimitiveBuffer* primBuffer;
GFXVertexBuffer* vertBuffer;

View file

@ -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 )

View file

@ -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++ )
{

View file

@ -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; }

View file

@ -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 );

View file

@ -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_

View file

@ -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
}

View file

@ -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;

View file

@ -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()

View file

@ -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;

View file

@ -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()

View file

@ -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_

View file

@ -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_

View file

@ -182,6 +182,7 @@ Material::Material()
mAlphaRef = 1;
mCastShadows = true;
mCastDynamicShadows = false;
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),

View file

@ -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();

View file

@ -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;

View file

@ -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
{

View file

@ -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

View file

@ -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_

View file

@ -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;
}

View file

@ -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;