mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-06 14:00:39 +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
|
|
@ -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_
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue