diff --git a/Engine/source/T3D/lightBase.cpp b/Engine/source/T3D/lightBase.cpp index dd168a483..8e351ed81 100644 --- a/Engine/source/T3D/lightBase.cpp +++ b/Engine/source/T3D/lightBase.cpp @@ -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 ); diff --git a/Engine/source/T3D/lightBase.h b/Engine/source/T3D/lightBase.h index a01926edb..2501c4ca8 100644 --- a/Engine/source/T3D/lightBase.h +++ b/Engine/source/T3D/lightBase.h @@ -56,7 +56,8 @@ protected: F32 mBrightness; bool mCastShadows; - + S32 mStaticRefreshFreq; + S32 mDynamicRefreshFreq; F32 mPriority; LightInfo *mLight; diff --git a/Engine/source/T3D/lightDescription.cpp b/Engine/source/T3D/lightDescription.cpp index 919f4418d..d88d2a682 100644 --- a/Engine/source/T3D/lightDescription.cpp +++ b/Engine/source/T3D/lightDescription.cpp @@ -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 ) diff --git a/Engine/source/T3D/lightDescription.h b/Engine/source/T3D/lightDescription.h index b24ff895a..fda00ebc2 100644 --- a/Engine/source/T3D/lightDescription.h +++ b/Engine/source/T3D/lightDescription.h @@ -101,6 +101,8 @@ public: F32 brightness; F32 range; bool castShadows; + S32 mStaticRefreshFreq; + S32 mDynamicRefreshFreq; LightAnimData *animationData; S32 animationDataId; diff --git a/Engine/source/T3D/pointLight.cpp b/Engine/source/T3D/pointLight.cpp index 4b2a9d983..7376e8adc 100644 --- a/Engine/source/T3D/pointLight.cpp +++ b/Engine/source/T3D/pointLight.cpp @@ -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. diff --git a/Engine/source/T3D/spotLight.cpp b/Engine/source/T3D/spotLight.cpp index 65e4a72ac..1ec22cd48 100644 --- a/Engine/source/T3D/spotLight.cpp +++ b/Engine/source/T3D/spotLight.cpp @@ -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 ); diff --git a/Engine/source/environment/scatterSky.cpp b/Engine/source/environment/scatterSky.cpp index 3e2d2d890..36ff48dfb 100644 --- a/Engine/source/environment/scatterSky.cpp +++ b/Engine/source/environment/scatterSky.cpp @@ -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 ); diff --git a/Engine/source/environment/scatterSky.h b/Engine/source/environment/scatterSky.h index 66177851d..4164a3725 100644 --- a/Engine/source/environment/scatterSky.h +++ b/Engine/source/environment/scatterSky.h @@ -207,6 +207,8 @@ protected: LightInfo *mLight; bool mCastShadows; + S32 mStaticRefreshFreq; + S32 mDynamicRefreshFreq; bool mDirty; LightFlareData *mFlareData; diff --git a/Engine/source/environment/sun.cpp b/Engine/source/environment/sun.cpp index 45181a27b..d79d923d6 100644 --- a/Engine/source/environment/sun.cpp +++ b/Engine/source/environment/sun.cpp @@ -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() diff --git a/Engine/source/environment/sun.h b/Engine/source/environment/sun.h index d82c45768..27ce97ae6 100644 --- a/Engine/source/environment/sun.h +++ b/Engine/source/environment/sun.h @@ -65,6 +65,8 @@ protected: F32 mEndElevation; bool mCastShadows; + S32 mStaticRefreshFreq; + S32 mDynamicRefreshFreq; LightInfo *mLight; diff --git a/Engine/source/forest/forestCell.cpp b/Engine/source/forest/forestCell.cpp index a2a4f36e6..b72d585e2 100644 --- a/Engine/source/forest/forestCell.cpp +++ b/Engine/source/forest/forestCell.cpp @@ -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(); } diff --git a/Engine/source/forest/forestRender.cpp b/Engine/source/forest/forestRender.cpp index 3fa2b3047..cae86da3f 100644 --- a/Engine/source/forest/forestRender.cpp +++ b/Engine/source/forest/forestRender.cpp @@ -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. diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 1f0286dd3..dd71afeb0 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -191,10 +191,11 @@ void AdvancedLightBinManager::addLight( LightInfo *light ) // Find a shadow map for this light, if it has one ShadowMapParams *lsp = light->getExtended(); 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 ); diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index ee2064885..879d62cbb 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -185,6 +185,7 @@ protected: { LightInfo* lightInfo; LightShadowMap* shadowMap; + LightShadowMap* dynamicShadowMap; LightMaterialInfo* lightMaterial; GFXPrimitiveBuffer* primBuffer; GFXVertexBuffer* vertBuffer; diff --git a/Engine/source/lighting/advanced/advancedLightManager.cpp b/Engine/source/lighting/advanced/advancedLightManager.cpp index ef4446a40..d82f4f69c 100644 --- a/Engine/source/lighting/advanced/advancedLightManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightManager.cpp @@ -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 ) diff --git a/Engine/source/lighting/lightInfo.cpp b/Engine/source/lighting/lightInfo.cpp index 1759ba24b..2ea958861 100644 --- a/Engine/source/lighting/lightInfo.cpp +++ b/Engine/source/lighting/lightInfo.cpp @@ -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++ ) { diff --git a/Engine/source/lighting/lightInfo.h b/Engine/source/lighting/lightInfo.h index 1dee8f0d0..e485dba70 100644 --- a/Engine/source/lighting/lightInfo.h +++ b/Engine/source/lighting/lightInfo.h @@ -131,6 +131,9 @@ protected: bool mCastShadows; + S32 mStaticRefreshFreq; + S32 mDynamicRefreshFreq; + ::Vector 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; } diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.cpp b/Engine/source/lighting/shadowMap/lightShadowMap.cpp index 3a85a0b40..53a6f4e8d 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/lightShadowMap.cpp @@ -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 ); diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.h b/Engine/source/lighting/shadowMap/lightShadowMap.h index af45b32fe..2cbb2ca5e 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.h +++ b/Engine/source/lighting/shadowMap/lightShadowMap.h @@ -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_ diff --git a/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp b/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp index 15a338db9..d276fe3a5 100644 --- a/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp @@ -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 > _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 > &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 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 hullVerts; + MathUtils::mBuildHull2D(projVertices, hullVerts); + + Vector 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 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 + +} diff --git a/Engine/source/lighting/shadowMap/pssmLightShadowMap.h b/Engine/source/lighting/shadowMap/pssmLightShadowMap.h index d2fffde8e..8ee883018 100644 --- a/Engine/source/lighting/shadowMap/pssmLightShadowMap.h +++ b/Engine/source/lighting/shadowMap/pssmLightShadowMap.h @@ -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 > &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; diff --git a/Engine/source/lighting/shadowMap/shadowMapManager.cpp b/Engine/source/lighting/shadowMap/shadowMapManager.cpp index cfcf75f81..7fd50cd78 100644 --- a/Engine/source/lighting/shadowMap/shadowMapManager.cpp +++ b/Engine/source/lighting/shadowMap/shadowMapManager.cpp @@ -86,6 +86,7 @@ Signal 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(); if ( params ) + { mCurrentShadowMap = params->getShadowMap(); + mCurrentDynamicShadowMap = params->getShadowMap(true); + } else + { mCurrentShadowMap = NULL; + mCurrentDynamicShadowMap = NULL; + } } void ShadowMapManager::activate() diff --git a/Engine/source/lighting/shadowMap/shadowMapManager.h b/Engine/source/lighting/shadowMap/shadowMapManager.h index 9319f3e36..a2e402e59 100644 --- a/Engine/source/lighting/shadowMap/shadowMapManager.h +++ b/Engine/source/lighting/shadowMap/shadowMapManager.h @@ -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; diff --git a/Engine/source/lighting/shadowMap/shadowMapPass.cpp b/Engine/source/lighting/shadowMap/shadowMapPass.cpp index 67eebc40c..7c17046e1 100644 --- a/Engine/source/lighting/shadowMap/shadowMapPass.cpp +++ b/Engine/source/lighting/shadowMap/shadowMapPass.cpp @@ -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 shadowMaps; - shadowMaps.reserve( mActiveLights ); + shadowMaps.reserve( mActiveLights * 2 ); for ( U32 i = 0; i < mActiveLights; i++ ) { ShadowMapParams *params = mLights[i]->getExtended(); @@ -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( 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() diff --git a/Engine/source/lighting/shadowMap/shadowMapPass.h b/Engine/source/lighting/shadowMap/shadowMapPass.h index 8689153cf..45e908c91 100644 --- a/Engine/source/lighting/shadowMap/shadowMapPass.h +++ b/Engine/source/lighting/shadowMap/shadowMapPass.h @@ -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 mShadowRPM; + SimObjectPtr 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_ diff --git a/Engine/source/materials/baseMaterialDefinition.h b/Engine/source/materials/baseMaterialDefinition.h index c1c033015..1022903c0 100644 --- a/Engine/source/materials/baseMaterialDefinition.h +++ b/Engine/source/materials/baseMaterialDefinition.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_ diff --git a/Engine/source/materials/materialDefinition.cpp b/Engine/source/materials/materialDefinition.cpp index 7e069c895..e27de0be2 100644 --- a/Engine/source/materials/materialDefinition.cpp +++ b/Engine/source/materials/materialDefinition.cpp @@ -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), diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 574472dbc..491b56cf0 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -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(); diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index 90994af69..765675a21 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -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; diff --git a/Engine/source/math/mPoint2.h b/Engine/source/math/mPoint2.h index f814ddbbc..d4c8180a1 100644 --- a/Engine/source/math/mPoint2.h +++ b/Engine/source/math/mPoint2.h @@ -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 { diff --git a/Engine/source/math/mathUtils.cpp b/Engine/source/math/mathUtils.cpp index 9f04b107e..f6086c5e4 100644 --- a/Engine/source/math/mathUtils.cpp +++ b/Engine/source/math/mathUtils.cpp @@ -1845,4 +1845,55 @@ U32 extrudePolygonEdgesFromPoint( const Point3F* vertices, U32 numVertices, cons return numPlanes; } +//----------------------------------------------------------------------------- + +void MathUtils::mBuildHull2D(const Vector _inPoints, Vector &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 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 diff --git a/Engine/source/math/mathUtils.h b/Engine/source/math/mathUtils.h index 86484c07b..ee7be9c2a 100644 --- a/Engine/source/math/mathUtils.h +++ b/Engine/source/math/mathUtils.h @@ -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 inPoints, Vector &hullPoints); + } // namespace MathUtils #endif // _MATHUTILS_H_ diff --git a/Engine/source/scene/culling/sceneCullingState.cpp b/Engine/source/scene/culling/sceneCullingState.cpp index ea53639d2..260b5e33f 100644 --- a/Engine/source/scene/culling/sceneCullingState.cpp +++ b/Engine/source/scene/culling/sceneCullingState.cpp @@ -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; } diff --git a/Engine/source/scene/culling/sceneCullingState.h b/Engine/source/scene/culling/sceneCullingState.h index b63b219c2..4361907ce 100644 --- a/Engine/source/scene/culling/sceneCullingState.h +++ b/Engine/source/scene/culling/sceneCullingState.h @@ -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; diff --git a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs index 7fda56235..2e73b6569 100644 --- a/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs @@ -62,9 +62,10 @@ new ShaderData( AL_VectorLightShader ) OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/vectorLightP.glsl"; samplerNames[0] = "$prePassBuffer"; - samplerNames[1] = "$ShadowMap"; - samplerNames[2] = "$ssaoMask"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[1] = "$shadowMap"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$ssaoMask"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -75,7 +76,8 @@ new CustomMaterial( AL_VectorLightMaterial ) stateBlock = AL_VectorLightState; sampler["prePassBuffer"] = "#prepass"; - sampler["ShadowMap"] = "$dynamiclight"; + sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["ssaoMask"] = "#ssaoMask"; target = "lightinfo"; @@ -128,8 +130,9 @@ new ShaderData( AL_PointLightShader ) samplerNames[0] = "$prePassBuffer"; samplerNames[1] = "$shadowMap"; - samplerNames[2] = "$cookieMap"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -141,6 +144,7 @@ new CustomMaterial( AL_PointLightMaterial ) sampler["prePassBuffer"] = "#prepass"; sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; target = "lightinfo"; @@ -159,8 +163,9 @@ new ShaderData( AL_SpotLightShader ) samplerNames[0] = "$prePassBuffer"; samplerNames[1] = "$shadowMap"; - samplerNames[2] = "$cookieMap"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -172,6 +177,7 @@ new CustomMaterial( AL_SpotLightMaterial ) sampler["prePassBuffer"] = "#prepass"; sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; target = "lightinfo"; diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/gl/pointLightP.glsl b/Templates/Empty/game/shaders/common/lighting/advanced/gl/pointLightP.glsl index 3bfd94900..92c9369a7 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/gl/pointLightP.glsl @@ -28,6 +28,7 @@ #include "../../../gl/lighting.glsl" #include "../../shadowMap/shadowMapIO_GLSL.h" #include "softShadow.glsl" +#include "../../../gl/torque.glsl" in vec4 wsEyeDir; in vec4 ssPos; @@ -107,6 +108,7 @@ uniform sampler2D prePassBuffer; uniform samplerCube shadowMap; #else uniform sampler2D shadowMap; + uniform sampler2D dynamicShadowMap; #endif uniform vec4 rtParams0; @@ -119,9 +121,10 @@ uniform vec2 lightAttenuation; uniform vec4 lightMapParams; uniform vec4 vsFarPlane; uniform mat3 viewToLightProj; +uniform mat3 dynamicViewToLightProj; uniform vec4 lightParams; uniform float shadowSoftness; - + out vec4 OUT_col; void main() @@ -175,7 +178,7 @@ void main() vec2 shadowCoord = decodeShadowCoord( tMul( viewToLightProj, -lightVec ) ).xy; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -183,17 +186,28 @@ void main() nDotL, lightParams.y ); + vec2 dynamicShadowCoord = decodeShadowCoord( tMul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); #endif #endif // !NO_SHADOW + vec3 lightcol = lightColor.rgb; #ifdef USE_COOKIE_TEX // Lookup the cookie sample. vec4 cookie = texture( cookieMap, tMul( viewToLightProj, -lightVec ) ); // Multiply the light with the cookie tex. - lightColor.rgb *= cookie.rgb; + lightcol *= cookie.rgb; // Use a maximum channel luminance to attenuate // the lighting else we get specular in the dark @@ -211,7 +225,7 @@ void main() normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; - vec3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + vec3 lightColorOut = lightMapParams.rgb * lightcol; vec4 addToResult = vec4(0.0); // TODO: This needs to be removed when lightmapping is disabled diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/gl/spotLightP.glsl b/Templates/Empty/game/shaders/common/lighting/advanced/gl/spotLightP.glsl index b3920ec9a..29c278508 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/gl/spotLightP.glsl @@ -27,6 +27,7 @@ #include "shadergen:/autogenConditioners.h" #include "softShadow.glsl" #include "../../../gl/lighting.glsl" +#include "../../../gl/torque.glsl" in vec4 wsEyeDir; in vec4 ssPos; @@ -45,6 +46,7 @@ uniform sampler2D cookieMap; uniform sampler2D prePassBuffer; uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; uniform vec4 rtParams0; @@ -59,6 +61,7 @@ uniform vec4 lightMapParams; uniform vec4 vsFarPlane; uniform mat4 viewToLightProj; +uniform mat4 dynamicViewToLightProj; uniform vec4 lightParams; uniform float shadowSoftness; @@ -70,7 +73,7 @@ void main() // Compute scene UV vec3 ssPos = IN_ssPos.xyz / IN_ssPos.w; vec2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); - + // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); vec3 normal = prepassSample.rgb; @@ -102,6 +105,10 @@ void main() vec2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); shadowCoord.y = 1.0f - shadowCoord.y; + // Get the dynamic shadow texture coordinate + vec4 dynpxlPosLightProj = tMul( dynamicViewToLightProj, vec4( viewSpacePos, 1 ) ); + vec2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; #ifdef NO_SHADOW float shadowed = 1.0; @@ -111,7 +118,7 @@ void main() // Get a linear depth from the light source. float distToLight = pxlPosLightProj.z / lightRange; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -119,15 +126,24 @@ void main() nDotL, lightParams.y ); + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); #endif // !NO_SHADOW + vec3 lightcol = lightColor.rgb; #ifdef USE_COOKIE_TEX // Lookup the cookie sample. vec4 cookie = texture( cookieMap, shadowCoord ); // Multiply the light with the cookie tex. - lightColor.rgb *= cookie.rgb; + lightcol *= cookie.rgb; // Use a maximum channel luminance to attenuate // the lighting else we get specular in the dark @@ -145,7 +161,7 @@ void main() normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; - vec3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + vec3 lightColorOut = lightMapParams.rgb * lightcol; vec4 addToResult = vec4(0.0); // TODO: This needs to be removed when lightmapping is disabled diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl b/Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl index eab364cd5..4eb4973a3 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl @@ -34,38 +34,162 @@ in vec2 uv0; in vec3 wsEyeRay; in vec3 vsEyeRay; -uniform sampler2D ShadowMap ; +uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; #ifdef USE_SSAO_MASK uniform sampler2D ssaoMask ; uniform vec4 rtParams2; #endif -uniform sampler2D prePassBuffer; +uniform sampler2D prePassBuffer; uniform vec3 lightDirection; uniform vec4 lightColor; uniform float lightBrightness; uniform vec4 lightAmbient; uniform vec3 eyePosWorld; -uniform mat4x4 worldToLightProj; -uniform vec4 scaleX; -uniform vec4 scaleY; -uniform vec4 offsetX; -uniform vec4 offsetY; +uniform mat4x4 eyeMat; uniform vec4 atlasXOffset; uniform vec4 atlasYOffset; uniform vec2 atlasScale; uniform vec4 zNearFarInvNearFar; uniform vec4 lightMapParams; uniform vec2 fadeStartLength; -uniform vec4 farPlaneScalePSSM; uniform vec4 overDarkPSSM; uniform float shadowSoftness; + +//static shadowMap +uniform mat4x4 worldToLightProj; +uniform vec4 scaleX; +uniform vec4 scaleY; +uniform vec4 offsetX; +uniform vec4 offsetY; +uniform vec4 farPlaneScalePSSM; + +//dynamic shadowMap +uniform mat4x4 dynamicWorldToLightProj; +uniform vec4 dynamicScaleX; +uniform vec4 dynamicScaleY; +uniform vec4 dynamicOffsetX; +uniform vec4 dynamicOffsetY; +uniform vec4 dynamicFarPlaneScalePSSM; + +vec4 AL_VectorLightShadowCast( sampler2D _sourceshadowMap, + vec2 _texCoord, + mat4 _worldToLightProj, + vec4 _worldPos, + vec4 _scaleX, vec4 _scaleY, + vec4 _offsetX, vec4 _offsetY, + vec4 _farPlaneScalePSSM, + vec4 _atlasXOffset, vec4 _atlasYOffset, + vec2 _atlasScale, + float _shadowSoftness, + float _dotNL , + vec4 _overDarkPSSM +) +{ + + // Compute shadow map coordinate + vec4 pxlPosLightProj = tMul(_worldToLightProj, _worldPos); + vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + + // Distance to light, in shadowMap space + float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; + + // Figure out which split to sample from. Basically, we compute the shadowMap sample coord + // for all of the splits and then check if its valid. + vec4 shadowCoordX = vec4( baseShadowCoord.x ); + vec4 shadowCoordY = vec4( baseShadowCoord.y ); + vec4 farPlaneDists = vec4( distToLight ); + shadowCoordX *= _scaleX; + shadowCoordY *= _scaleY; + shadowCoordX += _offsetX; + shadowCoordY += _offsetY; + farPlaneDists *= _farPlaneScalePSSM; + + // If the shadow sample is within -1..1 and the distance + // to the light for this pixel is less than the far plane + // of the split, use it. + vec4 finalMask; + if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && + shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && + farPlaneDists.x < 1.0 ) + finalMask = vec4(1, 0, 0, 0); + + else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && + shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && + farPlaneDists.y < 1.0 ) + finalMask = vec4(0, 1, 0, 0); + + else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && + shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && + farPlaneDists.z < 1.0 ) + finalMask = vec4(0, 0, 1, 0); + + else + finalMask = vec4(0, 0, 0, 1); + + vec3 debugColor = vec3(0); + + #ifdef NO_SHADOW + debugColor = vec3(1.0); + #endif + + #ifdef PSSM_DEBUG_RENDER + if ( finalMask.x > 0 ) + debugColor += vec3( 1, 0, 0 ); + else if ( finalMask.y > 0 ) + debugColor += vec3( 0, 1, 0 ); + else if ( finalMask.z > 0 ) + debugColor += vec3( 0, 0, 1 ); + else if ( finalMask.w > 0 ) + debugColor += vec3( 1, 1, 0 ); + #endif + + // Here we know what split we're sampling from, so recompute the _texCoord location + // Yes, we could just use the result from above, but doing it this way actually saves + // shader instructions. + vec2 finalScale; + finalScale.x = dot(finalMask, _scaleX); + finalScale.y = dot(finalMask, _scaleY); + + vec2 finalOffset; + finalOffset.x = dot(finalMask, _offsetX); + finalOffset.y = dot(finalMask, _offsetY); + + vec2 shadowCoord; + shadowCoord = baseShadowCoord * finalScale; + shadowCoord += finalOffset; + + // Convert to _texCoord space + shadowCoord = 0.5 * shadowCoord + vec2(0.5, 0.5); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Move around inside of atlas + vec2 aOffset; + aOffset.x = dot(finalMask, _atlasXOffset); + aOffset.y = dot(finalMask, _atlasYOffset); + + shadowCoord *= _atlasScale; + shadowCoord += aOffset; + + // Each split has a different far plane, take this into account. + float farPlaneScale = dot( _farPlaneScalePSSM, finalMask ); + distToLight *= farPlaneScale; + + return vec4(debugColor, + softShadow_filter( _sourceshadowMap, + _texCoord, + shadowCoord, + farPlaneScale * _shadowSoftness, + distToLight, + _dotNL, + dot( finalMask, _overDarkPSSM ) ) ); +} out vec4 OUT_col; - void main() -{ +{ // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 ); vec3 normal = prepassSample.rgb; @@ -92,102 +216,52 @@ void main() #else - // Compute shadow map coordinate - vec4 pxlPosLightProj = tMul(worldToLightProj, worldPos); - vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + vec4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap, + uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); - // Distance to light, in shadowmap space - float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; - - // Figure out which split to sample from. Basically, we compute the shadowmap sample coord - // for all of the splits and then check if its valid. - vec4 shadowCoordX = vec4( baseShadowCoord.x ); - vec4 shadowCoordY = vec4( baseShadowCoord.y ); - vec4 farPlaneDists = vec4( distToLight ); - shadowCoordX *= scaleX; - shadowCoordY *= scaleY; - shadowCoordX += offsetX; - shadowCoordY += offsetY; - farPlaneDists *= farPlaneScalePSSM; + + vec4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap, + uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); - // If the shadow sample is within -1..1 and the distance - // to the light for this pixel is less than the far plane - // of the split, use it. - vec4 finalMask; - if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && - shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && - farPlaneDists.x < 1.0 ) - finalMask = vec4(1, 0, 0, 0); - - else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && - shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && - farPlaneDists.y < 1.0 ) - finalMask = vec4(0, 1, 0, 0); - - else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && - shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && - farPlaneDists.z < 1.0 ) - finalMask = vec4(0, 0, 1, 0); - - else - finalMask = vec4(0, 0, 0, 1); - - + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + #ifdef PSSM_DEBUG_RENDER - if ( finalMask.x > 0 ) - debugColor += vec3( 1, 0, 0 ); - else if ( finalMask.y > 0 ) - debugColor += vec3( 0, 1, 0 ); - else if ( finalMask.z > 0 ) - debugColor += vec3( 0, 0, 1 ); - else if ( finalMask.w > 0 ) - debugColor += vec3( 1, 1, 0 ); + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; #endif - - // Here we know what split we're sampling from, so recompute the texcoord location - // Yes, we could just use the result from above, but doing it this way actually saves - // shader instructions. - vec2 finalScale; - finalScale.x = dot(finalMask, scaleX); - finalScale.y = dot(finalMask, scaleY); - - vec2 finalOffset; - finalOffset.x = dot(finalMask, offsetX); - finalOffset.y = dot(finalMask, offsetY); - - vec2 shadowCoord; - shadowCoord = baseShadowCoord * finalScale; - shadowCoord += finalOffset; - - // Convert to texcoord space - shadowCoord = 0.5 * shadowCoord + vec2(0.5, 0.5); - shadowCoord.y = 1.0f - shadowCoord.y; - - // Move around inside of atlas - vec2 aOffset; - aOffset.x = dot(finalMask, atlasXOffset); - aOffset.y = dot(finalMask, atlasYOffset); - - shadowCoord *= atlasScale; - shadowCoord += aOffset; - - // Each split has a different far plane, take this into account. - float farPlaneScale = dot( farPlaneScalePSSM, finalMask ); - distToLight *= farPlaneScale; - - float shadowed = softShadow_filter( ShadowMap, - uv0.xy, - shadowCoord, - farPlaneScale * shadowSoftness, - distToLight, - dotNL, - dot( finalMask, overDarkPSSM ) ); - + // Fade out the shadow at the end of the range. vec4 zDist = vec4(zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; - shadowed = mix( shadowed, 1.0, saturate( fadeOutAmt ) ); - + + static_shadowed = mix( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = mix( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); + #ifdef PSSM_DEBUG_RENDER if ( fadeOutAmt > 1.0 ) debugColor = vec3(1.0); @@ -228,7 +302,7 @@ void main() #ifdef PSSM_DEBUG_RENDER lightColorOut = debugColor; #endif - + OUT_col = lightinfoCondition( lightColorOut, Sat_NL_Att, specular, addToResult ); } diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/pointLightP.hlsl b/Templates/Empty/game/shaders/common/lighting/advanced/pointLightP.hlsl index fbfced097..48c0d76e3 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/pointLightP.hlsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/pointLightP.hlsl @@ -27,7 +27,7 @@ #include "../../lighting.hlsl" #include "../shadowMap/shadowMapIO_HLSL.h" #include "softShadow.hlsl" - +#include "../../torque.hlsl" struct ConvexConnectP { @@ -40,7 +40,7 @@ struct ConvexConnectP #ifdef USE_COOKIE_TEX /// The texture for cookie rendering. -uniform samplerCUBE cookieMap : register(S2); +uniform samplerCUBE cookieMap : register(S3); #endif @@ -114,6 +114,7 @@ float4 main( ConvexConnectP IN, uniform samplerCUBE shadowMap : register(S1), #else uniform sampler2D shadowMap : register(S1), + uniform sampler2D dynamicShadowMap : register(S2), #endif uniform float4 rtParams0, @@ -127,6 +128,7 @@ float4 main( ConvexConnectP IN, uniform float4 vsFarPlane, uniform float3x3 viewToLightProj, + uniform float3x3 dynamicViewToLightProj, uniform float4 lightParams, uniform float shadowSoftness ) : COLOR0 @@ -134,7 +136,7 @@ float4 main( ConvexConnectP IN, // Compute scene UV float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); - + // Sample/unpack the normal/z data float4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); float3 normal = prepassSample.rgb; @@ -178,9 +180,9 @@ float4 main( ConvexConnectP IN, #else + // Static float2 shadowCoord = decodeShadowCoord( mul( viewToLightProj, -lightVec ) ).xy; - - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -188,17 +190,30 @@ float4 main( ConvexConnectP IN, nDotL, lightParams.y ); + // Dynamic + float2 dynamicShadowCoord = decodeShadowCoord( mul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); + #endif #endif // !NO_SHADOW + float3 lightcol = lightColor.rgb; #ifdef USE_COOKIE_TEX // Lookup the cookie sample. float4 cookie = texCUBE( cookieMap, mul( viewToLightProj, -lightVec ) ); // Multiply the light with the cookie tex. - lightColor.rgb *= cookie.rgb; + lightcol *= cookie.rgb; // Use a maximum channel luminance to attenuate // the lighting else we get specular in the dark @@ -216,7 +231,7 @@ float4 main( ConvexConnectP IN, normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; - float3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + float3 lightColorOut = lightMapParams.rgb * lightcol; float4 addToResult = 0.0; // TODO: This needs to be removed when lightmapping is disabled diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/softShadow.hlsl b/Templates/Empty/game/shaders/common/lighting/advanced/softShadow.hlsl index 0e8ecabaa..36bffbfd9 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/softShadow.hlsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/softShadow.hlsl @@ -69,7 +69,7 @@ static float2 sNonUniformTaps[NUM_PRE_TAPS] = /// The texture used to do per-pixel pseudorandom /// rotations of the filter taps. -uniform sampler2D gTapRotationTex : register(S3); +uniform sampler2D gTapRotationTex : register(S4); float softShadow_sampleTaps( sampler2D shadowMap, diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/spotLightP.hlsl b/Templates/Empty/game/shaders/common/lighting/advanced/spotLightP.hlsl index 88e35ad3a..33c7f333e 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/spotLightP.hlsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/spotLightP.hlsl @@ -27,7 +27,7 @@ #include "../../lighting.hlsl" #include "../shadowMap/shadowMapIO_HLSL.h" #include "softShadow.hlsl" - +#include "../../torque.hlsl" struct ConvexConnectP { @@ -39,7 +39,7 @@ struct ConvexConnectP #ifdef USE_COOKIE_TEX /// The texture for cookie rendering. -uniform sampler2D cookieMap : register(S2); +uniform sampler2D cookieMap : register(S3); #endif @@ -48,6 +48,7 @@ float4 main( ConvexConnectP IN, uniform sampler2D prePassBuffer : register(S0), uniform sampler2D shadowMap : register(S1), + uniform sampler2D dynamicShadowMap : register(S2), uniform float4 rtParams0, @@ -62,6 +63,7 @@ float4 main( ConvexConnectP IN, uniform float4 vsFarPlane, uniform float4x4 viewToLightProj, + uniform float4x4 dynamicViewToLightProj, uniform float4 lightParams, uniform float shadowSoftness ) : COLOR0 @@ -101,6 +103,11 @@ float4 main( ConvexConnectP IN, float2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); shadowCoord.y = 1.0f - shadowCoord.y; + // Get the dynamic shadow texture coordinate + float4 dynpxlPosLightProj = mul( dynamicViewToLightProj, float4( viewSpacePos, 1 ) ); + float2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; + #ifdef NO_SHADOW float shadowed = 1.0; @@ -110,23 +117,32 @@ float4 main( ConvexConnectP IN, // Get a linear depth from the light source. float distToLight = pxlPosLightProj.z / lightRange; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, distToLight, nDotL, lightParams.y ); - + + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); #endif // !NO_SHADOW + float3 lightcol = lightColor.rgb; #ifdef USE_COOKIE_TEX // Lookup the cookie sample. float4 cookie = tex2D( cookieMap, shadowCoord ); // Multiply the light with the cookie tex. - lightColor.rgb *= cookie.rgb; + lightcol *= cookie.rgb; // Use a maximum channel luminance to attenuate // the lighting else we get specular in the dark @@ -144,7 +160,7 @@ float4 main( ConvexConnectP IN, normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; - float3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + float3 lightColorOut = lightMapParams.rgb * lightcol; float4 addToResult = 0.0; // TODO: This needs to be removed when lightmapping is disabled diff --git a/Templates/Empty/game/shaders/common/lighting/advanced/vectorLightP.hlsl b/Templates/Empty/game/shaders/common/lighting/advanced/vectorLightP.hlsl index 266cc6438..1b4548575 100644 --- a/Templates/Empty/game/shaders/common/lighting/advanced/vectorLightP.hlsl +++ b/Templates/Empty/game/shaders/common/lighting/advanced/vectorLightP.hlsl @@ -30,68 +30,31 @@ #include "softShadow.hlsl" -uniform sampler2D ShadowMap : register(S1); +uniform sampler2D shadowMap : register(S1); +uniform sampler2D dynamicShadowMap : register(S2); #ifdef USE_SSAO_MASK -uniform sampler2D ssaoMask : register(S2); +uniform sampler2D ssaoMask : register(S3); uniform float4 rtParams2; #endif - -float4 main( FarFrustumQuadConnectP IN, - - uniform sampler2D prePassBuffer : register(S0), - - uniform float3 lightDirection, - uniform float4 lightColor, - uniform float lightBrightness, - uniform float4 lightAmbient, - - uniform float3 eyePosWorld, - - uniform float4x4 worldToLightProj, - - uniform float4 scaleX, - uniform float4 scaleY, - uniform float4 offsetX, - uniform float4 offsetY, - uniform float4 atlasXOffset, - uniform float4 atlasYOffset, - uniform float2 atlasScale, - uniform float4 zNearFarInvNearFar, - uniform float4 lightMapParams, - - uniform float2 fadeStartLength, - uniform float4 farPlaneScalePSSM, - uniform float4 overDarkPSSM, - uniform float shadowSoftness ) : COLOR0 +float4 AL_VectorLightShadowCast( sampler2D sourceShadowMap, + float2 texCoord, + float4x4 worldToLightProj, + float4 worldPos, + float4 scaleX, + float4 scaleY, + float4 offsetX, + float4 offsetY, + float4 farPlaneScalePSSM, + float4 atlasXOffset, + float4 atlasYOffset, + float2 atlasScale, + float shadowSoftness, + float dotNL , + float4 overDarkPSSM +) { - // Sample/unpack the normal/z data - float4 prepassSample = prepassUncondition( prePassBuffer, IN.uv0 ); - float3 normal = prepassSample.rgb; - float depth = prepassSample.a; - - // Use eye ray to get ws pos - float4 worldPos = float4(eyePosWorld + IN.wsEyeRay * depth, 1.0f); - - // Get the light attenuation. - float dotNL = dot(-lightDirection, normal); - - #ifdef PSSM_DEBUG_RENDER - float3 debugColor = 0; - #endif - - #ifdef NO_SHADOW - - // Fully unshadowed. - float shadowed = 1.0; - - #ifdef PSSM_DEBUG_RENDER - debugColor = 1.0; - #endif - - #else - // Compute shadow map coordinate float4 pxlPosLightProj = mul(worldToLightProj, worldPos); float2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; @@ -132,6 +95,11 @@ float4 main( FarFrustumQuadConnectP IN, else finalMask = float4(0, 0, 0, 1); + float3 debugColor = float3(0,0,0); + + #ifdef NO_SHADOW + debugColor = float3(1.0,1.0,1.0); + #endif #ifdef PSSM_DEBUG_RENDER if ( finalMask.x > 0 ) @@ -174,19 +142,125 @@ float4 main( FarFrustumQuadConnectP IN, // Each split has a different far plane, take this into account. float farPlaneScale = dot( farPlaneScalePSSM, finalMask ); distToLight *= farPlaneScale; + + return float4(debugColor, + softShadow_filter( sourceShadowMap, + texCoord, + shadowCoord, + farPlaneScale * shadowSoftness, + distToLight, + dotNL, + dot( finalMask, overDarkPSSM ) ) ); +}; + +float4 main( FarFrustumQuadConnectP IN, + + uniform sampler2D prePassBuffer : register(S0), + + uniform float3 lightDirection, + uniform float4 lightColor, + uniform float lightBrightness, + uniform float4 lightAmbient, + uniform float4x4 eyeMat, + + uniform float3 eyePosWorld, + uniform float4 atlasXOffset, + uniform float4 atlasYOffset, + uniform float2 atlasScale, + uniform float4 zNearFarInvNearFar, + uniform float4 lightMapParams, + uniform float2 fadeStartLength, + uniform float4 overDarkPSSM, + uniform float shadowSoftness, + + // Static Shadows + uniform float4x4 worldToLightProj, + uniform float4 scaleX, + uniform float4 scaleY, + uniform float4 offsetX, + uniform float4 offsetY, + uniform float4 farPlaneScalePSSM, + + // Dynamic Shadows + uniform float4x4 dynamicWorldToLightProj, + uniform float4 dynamicScaleX, + uniform float4 dynamicScaleY, + uniform float4 dynamicOffsetX, + uniform float4 dynamicOffsetY, + uniform float4 dynamicFarPlaneScalePSSM + + ) : COLOR0 +{ + // Sample/unpack the normal/z data + float4 prepassSample = prepassUncondition( prePassBuffer, IN.uv0 ); + float3 normal = prepassSample.rgb; + float depth = prepassSample.a; + + // Use eye ray to get ws pos + float4 worldPos = float4(eyePosWorld + IN.wsEyeRay * depth, 1.0f); + + // Get the light attenuation. + float dotNL = dot(-lightDirection, normal); + + #ifdef PSSM_DEBUG_RENDER + float3 debugColor = float3(0,0,0); + #endif + + #ifdef NO_SHADOW + + // Fully unshadowed. + float shadowed = 1.0; + + #ifdef PSSM_DEBUG_RENDER + debugColor = float3(1.0,1.0,1.0); + #endif + + #else - float shadowed = softShadow_filter( ShadowMap, - IN.uv0.xy, - shadowCoord, - farPlaneScale * shadowSoftness, - distToLight, - dotNL, - dot( finalMask, overDarkPSSM ) ); + float4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap, + IN.uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + + float4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap, + IN.uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + + #ifdef PSSM_DEBUG_RENDER + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; + #endif // Fade out the shadow at the end of the range. float4 zDist = (zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; - shadowed = lerp( shadowed, 1.0, saturate( fadeOutAmt ) ); + + static_shadowed = lerp( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = lerp( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); #ifdef PSSM_DEBUG_RENDER if ( fadeOutAmt > 1.0 ) diff --git a/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui b/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui index b4b006904..2062f43f3 100644 --- a/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui +++ b/Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui @@ -3309,7 +3309,7 @@ HorizSizing = "width"; VertSizing = "bottom"; Position = "0 0"; - Extent = "210 71"; + Extent = "210 89"; new GuiPopUpMenuCtrl() { internalName = "blendingTypePopUp"; @@ -3480,7 +3480,7 @@ Visible = "1"; Command = "MaterialEditorGui.updateActiveMaterial(\"castShadows\", $ThisControl.getValue());"; tooltipprofile = "ToolsGuiDefaultProfile"; - ToolTip = "Alows object to cast shadows."; + ToolTip = "Object casts shadows."; hovertime = "1000"; text = "Cast Shadows"; groupNum = "-1"; @@ -3488,6 +3488,29 @@ useMouseEvents = "0"; useInactiveState = "0"; }; + new GuiCheckBoxCtrl() { + canSaveDynamicFields = "0"; + internalName = "castDynamicShadows"; + Enabled = "1"; + isContainer = "0"; + Profile = "ToolsGuiCheckBoxProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "3 70"; + Extent = "112 16"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + Command = "MaterialEditorGui.updateActiveMaterial(\"castDynamicShadows\", $ThisControl.getValue());"; + tooltipprofile = "ToolsGuiDefaultProfile"; + ToolTip = "Object casts dynamic shadows."; + hovertime = "1000"; + text = "Dynamic Shadows"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + useInactiveState = "0"; + }; new GuiCheckBoxCtrl() { canSaveDynamicFields = "0"; internalName = "doubleSidedCheckBox"; diff --git a/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs index 6b055d05c..be7d55c39 100644 --- a/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -754,6 +754,7 @@ function MaterialEditorGui::guiSync( %this, %material ) MaterialEditorPropertiesWindow-->transZWriteCheckBox.setValue((%material).translucentZWrite); MaterialEditorPropertiesWindow-->alphaTestCheckBox.setValue((%material).alphaTest); MaterialEditorPropertiesWindow-->castShadows.setValue((%material).castShadows); + MaterialEditorPropertiesWindow-->castDynamicShadows.setValue((%material).castDynamicShadows); MaterialEditorPropertiesWindow-->translucentCheckbox.setValue((%material).translucent); switch$((%material).translucentBlendOp) diff --git a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs index 7fda56235..2e73b6569 100644 --- a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs @@ -62,9 +62,10 @@ new ShaderData( AL_VectorLightShader ) OGLPixelShaderFile = "shaders/common/lighting/advanced/gl/vectorLightP.glsl"; samplerNames[0] = "$prePassBuffer"; - samplerNames[1] = "$ShadowMap"; - samplerNames[2] = "$ssaoMask"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[1] = "$shadowMap"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$ssaoMask"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -75,7 +76,8 @@ new CustomMaterial( AL_VectorLightMaterial ) stateBlock = AL_VectorLightState; sampler["prePassBuffer"] = "#prepass"; - sampler["ShadowMap"] = "$dynamiclight"; + sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["ssaoMask"] = "#ssaoMask"; target = "lightinfo"; @@ -128,8 +130,9 @@ new ShaderData( AL_PointLightShader ) samplerNames[0] = "$prePassBuffer"; samplerNames[1] = "$shadowMap"; - samplerNames[2] = "$cookieMap"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -141,6 +144,7 @@ new CustomMaterial( AL_PointLightMaterial ) sampler["prePassBuffer"] = "#prepass"; sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; target = "lightinfo"; @@ -159,8 +163,9 @@ new ShaderData( AL_SpotLightShader ) samplerNames[0] = "$prePassBuffer"; samplerNames[1] = "$shadowMap"; - samplerNames[2] = "$cookieMap"; - samplerNames[3] = "$gTapRotationTex"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; pixVersion = 3.0; }; @@ -172,6 +177,7 @@ new CustomMaterial( AL_SpotLightMaterial ) sampler["prePassBuffer"] = "#prepass"; sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; sampler["cookieMap"] = "$dynamiclightmask"; target = "lightinfo"; diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl index 2c8e43736..92c9369a7 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl @@ -28,6 +28,7 @@ #include "../../../gl/lighting.glsl" #include "../../shadowMap/shadowMapIO_GLSL.h" #include "softShadow.glsl" +#include "../../../gl/torque.glsl" in vec4 wsEyeDir; in vec4 ssPos; @@ -107,6 +108,7 @@ uniform sampler2D prePassBuffer; uniform samplerCube shadowMap; #else uniform sampler2D shadowMap; + uniform sampler2D dynamicShadowMap; #endif uniform vec4 rtParams0; @@ -119,6 +121,7 @@ uniform vec2 lightAttenuation; uniform vec4 lightMapParams; uniform vec4 vsFarPlane; uniform mat3 viewToLightProj; +uniform mat3 dynamicViewToLightProj; uniform vec4 lightParams; uniform float shadowSoftness; @@ -175,7 +178,7 @@ void main() vec2 shadowCoord = decodeShadowCoord( tMul( viewToLightProj, -lightVec ) ).xy; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -183,6 +186,16 @@ void main() nDotL, lightParams.y ); + vec2 dynamicShadowCoord = decodeShadowCoord( tMul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); #endif #endif // !NO_SHADOW diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl index 91bc5915a..29c278508 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl @@ -27,6 +27,7 @@ #include "shadergen:/autogenConditioners.h" #include "softShadow.glsl" #include "../../../gl/lighting.glsl" +#include "../../../gl/torque.glsl" in vec4 wsEyeDir; in vec4 ssPos; @@ -45,6 +46,7 @@ uniform sampler2D cookieMap; uniform sampler2D prePassBuffer; uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; uniform vec4 rtParams0; @@ -59,6 +61,7 @@ uniform vec4 lightMapParams; uniform vec4 vsFarPlane; uniform mat4 viewToLightProj; +uniform mat4 dynamicViewToLightProj; uniform vec4 lightParams; uniform float shadowSoftness; @@ -70,7 +73,7 @@ void main() // Compute scene UV vec3 ssPos = IN_ssPos.xyz / IN_ssPos.w; vec2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); - + // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); vec3 normal = prepassSample.rgb; @@ -102,6 +105,10 @@ void main() vec2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); shadowCoord.y = 1.0f - shadowCoord.y; + // Get the dynamic shadow texture coordinate + vec4 dynpxlPosLightProj = tMul( dynamicViewToLightProj, vec4( viewSpacePos, 1 ) ); + vec2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; #ifdef NO_SHADOW float shadowed = 1.0; @@ -111,7 +118,7 @@ void main() // Get a linear depth from the light source. float distToLight = pxlPosLightProj.z / lightRange; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -119,6 +126,14 @@ void main() nDotL, lightParams.y ); + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); #endif // !NO_SHADOW vec3 lightcol = lightColor.rgb; diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl index eab364cd5..4eb4973a3 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl @@ -34,38 +34,162 @@ in vec2 uv0; in vec3 wsEyeRay; in vec3 vsEyeRay; -uniform sampler2D ShadowMap ; +uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; #ifdef USE_SSAO_MASK uniform sampler2D ssaoMask ; uniform vec4 rtParams2; #endif -uniform sampler2D prePassBuffer; +uniform sampler2D prePassBuffer; uniform vec3 lightDirection; uniform vec4 lightColor; uniform float lightBrightness; uniform vec4 lightAmbient; uniform vec3 eyePosWorld; -uniform mat4x4 worldToLightProj; -uniform vec4 scaleX; -uniform vec4 scaleY; -uniform vec4 offsetX; -uniform vec4 offsetY; +uniform mat4x4 eyeMat; uniform vec4 atlasXOffset; uniform vec4 atlasYOffset; uniform vec2 atlasScale; uniform vec4 zNearFarInvNearFar; uniform vec4 lightMapParams; uniform vec2 fadeStartLength; -uniform vec4 farPlaneScalePSSM; uniform vec4 overDarkPSSM; uniform float shadowSoftness; + +//static shadowMap +uniform mat4x4 worldToLightProj; +uniform vec4 scaleX; +uniform vec4 scaleY; +uniform vec4 offsetX; +uniform vec4 offsetY; +uniform vec4 farPlaneScalePSSM; + +//dynamic shadowMap +uniform mat4x4 dynamicWorldToLightProj; +uniform vec4 dynamicScaleX; +uniform vec4 dynamicScaleY; +uniform vec4 dynamicOffsetX; +uniform vec4 dynamicOffsetY; +uniform vec4 dynamicFarPlaneScalePSSM; + +vec4 AL_VectorLightShadowCast( sampler2D _sourceshadowMap, + vec2 _texCoord, + mat4 _worldToLightProj, + vec4 _worldPos, + vec4 _scaleX, vec4 _scaleY, + vec4 _offsetX, vec4 _offsetY, + vec4 _farPlaneScalePSSM, + vec4 _atlasXOffset, vec4 _atlasYOffset, + vec2 _atlasScale, + float _shadowSoftness, + float _dotNL , + vec4 _overDarkPSSM +) +{ + + // Compute shadow map coordinate + vec4 pxlPosLightProj = tMul(_worldToLightProj, _worldPos); + vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + + // Distance to light, in shadowMap space + float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; + + // Figure out which split to sample from. Basically, we compute the shadowMap sample coord + // for all of the splits and then check if its valid. + vec4 shadowCoordX = vec4( baseShadowCoord.x ); + vec4 shadowCoordY = vec4( baseShadowCoord.y ); + vec4 farPlaneDists = vec4( distToLight ); + shadowCoordX *= _scaleX; + shadowCoordY *= _scaleY; + shadowCoordX += _offsetX; + shadowCoordY += _offsetY; + farPlaneDists *= _farPlaneScalePSSM; + + // If the shadow sample is within -1..1 and the distance + // to the light for this pixel is less than the far plane + // of the split, use it. + vec4 finalMask; + if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && + shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && + farPlaneDists.x < 1.0 ) + finalMask = vec4(1, 0, 0, 0); + + else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && + shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && + farPlaneDists.y < 1.0 ) + finalMask = vec4(0, 1, 0, 0); + + else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && + shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && + farPlaneDists.z < 1.0 ) + finalMask = vec4(0, 0, 1, 0); + + else + finalMask = vec4(0, 0, 0, 1); + + vec3 debugColor = vec3(0); + + #ifdef NO_SHADOW + debugColor = vec3(1.0); + #endif + + #ifdef PSSM_DEBUG_RENDER + if ( finalMask.x > 0 ) + debugColor += vec3( 1, 0, 0 ); + else if ( finalMask.y > 0 ) + debugColor += vec3( 0, 1, 0 ); + else if ( finalMask.z > 0 ) + debugColor += vec3( 0, 0, 1 ); + else if ( finalMask.w > 0 ) + debugColor += vec3( 1, 1, 0 ); + #endif + + // Here we know what split we're sampling from, so recompute the _texCoord location + // Yes, we could just use the result from above, but doing it this way actually saves + // shader instructions. + vec2 finalScale; + finalScale.x = dot(finalMask, _scaleX); + finalScale.y = dot(finalMask, _scaleY); + + vec2 finalOffset; + finalOffset.x = dot(finalMask, _offsetX); + finalOffset.y = dot(finalMask, _offsetY); + + vec2 shadowCoord; + shadowCoord = baseShadowCoord * finalScale; + shadowCoord += finalOffset; + + // Convert to _texCoord space + shadowCoord = 0.5 * shadowCoord + vec2(0.5, 0.5); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Move around inside of atlas + vec2 aOffset; + aOffset.x = dot(finalMask, _atlasXOffset); + aOffset.y = dot(finalMask, _atlasYOffset); + + shadowCoord *= _atlasScale; + shadowCoord += aOffset; + + // Each split has a different far plane, take this into account. + float farPlaneScale = dot( _farPlaneScalePSSM, finalMask ); + distToLight *= farPlaneScale; + + return vec4(debugColor, + softShadow_filter( _sourceshadowMap, + _texCoord, + shadowCoord, + farPlaneScale * _shadowSoftness, + distToLight, + _dotNL, + dot( finalMask, _overDarkPSSM ) ) ); +} out vec4 OUT_col; - void main() -{ +{ // Sample/unpack the normal/z data vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 ); vec3 normal = prepassSample.rgb; @@ -92,102 +216,52 @@ void main() #else - // Compute shadow map coordinate - vec4 pxlPosLightProj = tMul(worldToLightProj, worldPos); - vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + vec4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap, + uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); - // Distance to light, in shadowmap space - float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; - - // Figure out which split to sample from. Basically, we compute the shadowmap sample coord - // for all of the splits and then check if its valid. - vec4 shadowCoordX = vec4( baseShadowCoord.x ); - vec4 shadowCoordY = vec4( baseShadowCoord.y ); - vec4 farPlaneDists = vec4( distToLight ); - shadowCoordX *= scaleX; - shadowCoordY *= scaleY; - shadowCoordX += offsetX; - shadowCoordY += offsetY; - farPlaneDists *= farPlaneScalePSSM; + + vec4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap, + uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); - // If the shadow sample is within -1..1 and the distance - // to the light for this pixel is less than the far plane - // of the split, use it. - vec4 finalMask; - if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && - shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && - farPlaneDists.x < 1.0 ) - finalMask = vec4(1, 0, 0, 0); - - else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && - shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && - farPlaneDists.y < 1.0 ) - finalMask = vec4(0, 1, 0, 0); - - else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && - shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && - farPlaneDists.z < 1.0 ) - finalMask = vec4(0, 0, 1, 0); - - else - finalMask = vec4(0, 0, 0, 1); - - + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + #ifdef PSSM_DEBUG_RENDER - if ( finalMask.x > 0 ) - debugColor += vec3( 1, 0, 0 ); - else if ( finalMask.y > 0 ) - debugColor += vec3( 0, 1, 0 ); - else if ( finalMask.z > 0 ) - debugColor += vec3( 0, 0, 1 ); - else if ( finalMask.w > 0 ) - debugColor += vec3( 1, 1, 0 ); + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; #endif - - // Here we know what split we're sampling from, so recompute the texcoord location - // Yes, we could just use the result from above, but doing it this way actually saves - // shader instructions. - vec2 finalScale; - finalScale.x = dot(finalMask, scaleX); - finalScale.y = dot(finalMask, scaleY); - - vec2 finalOffset; - finalOffset.x = dot(finalMask, offsetX); - finalOffset.y = dot(finalMask, offsetY); - - vec2 shadowCoord; - shadowCoord = baseShadowCoord * finalScale; - shadowCoord += finalOffset; - - // Convert to texcoord space - shadowCoord = 0.5 * shadowCoord + vec2(0.5, 0.5); - shadowCoord.y = 1.0f - shadowCoord.y; - - // Move around inside of atlas - vec2 aOffset; - aOffset.x = dot(finalMask, atlasXOffset); - aOffset.y = dot(finalMask, atlasYOffset); - - shadowCoord *= atlasScale; - shadowCoord += aOffset; - - // Each split has a different far plane, take this into account. - float farPlaneScale = dot( farPlaneScalePSSM, finalMask ); - distToLight *= farPlaneScale; - - float shadowed = softShadow_filter( ShadowMap, - uv0.xy, - shadowCoord, - farPlaneScale * shadowSoftness, - distToLight, - dotNL, - dot( finalMask, overDarkPSSM ) ); - + // Fade out the shadow at the end of the range. vec4 zDist = vec4(zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; - shadowed = mix( shadowed, 1.0, saturate( fadeOutAmt ) ); - + + static_shadowed = mix( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = mix( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); + #ifdef PSSM_DEBUG_RENDER if ( fadeOutAmt > 1.0 ) debugColor = vec3(1.0); @@ -228,7 +302,7 @@ void main() #ifdef PSSM_DEBUG_RENDER lightColorOut = debugColor; #endif - + OUT_col = lightinfoCondition( lightColorOut, Sat_NL_Att, specular, addToResult ); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl index ff1f3d437..48c0d76e3 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl @@ -27,7 +27,7 @@ #include "../../lighting.hlsl" #include "../shadowMap/shadowMapIO_HLSL.h" #include "softShadow.hlsl" - +#include "../../torque.hlsl" struct ConvexConnectP { @@ -40,7 +40,7 @@ struct ConvexConnectP #ifdef USE_COOKIE_TEX /// The texture for cookie rendering. -uniform samplerCUBE cookieMap : register(S2); +uniform samplerCUBE cookieMap : register(S3); #endif @@ -114,6 +114,7 @@ float4 main( ConvexConnectP IN, uniform samplerCUBE shadowMap : register(S1), #else uniform sampler2D shadowMap : register(S1), + uniform sampler2D dynamicShadowMap : register(S2), #endif uniform float4 rtParams0, @@ -127,6 +128,7 @@ float4 main( ConvexConnectP IN, uniform float4 vsFarPlane, uniform float3x3 viewToLightProj, + uniform float3x3 dynamicViewToLightProj, uniform float4 lightParams, uniform float shadowSoftness ) : COLOR0 @@ -134,7 +136,7 @@ float4 main( ConvexConnectP IN, // Compute scene UV float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); - + // Sample/unpack the normal/z data float4 prepassSample = prepassUncondition( prePassBuffer, uvScene ); float3 normal = prepassSample.rgb; @@ -178,9 +180,9 @@ float4 main( ConvexConnectP IN, #else + // Static float2 shadowCoord = decodeShadowCoord( mul( viewToLightProj, -lightVec ) ).xy; - - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, @@ -188,6 +190,18 @@ float4 main( ConvexConnectP IN, nDotL, lightParams.y ); + // Dynamic + float2 dynamicShadowCoord = decodeShadowCoord( mul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); + #endif #endif // !NO_SHADOW diff --git a/Templates/Full/game/shaders/common/lighting/advanced/softShadow.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/softShadow.hlsl index 0e8ecabaa..36bffbfd9 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/softShadow.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/softShadow.hlsl @@ -69,7 +69,7 @@ static float2 sNonUniformTaps[NUM_PRE_TAPS] = /// The texture used to do per-pixel pseudorandom /// rotations of the filter taps. -uniform sampler2D gTapRotationTex : register(S3); +uniform sampler2D gTapRotationTex : register(S4); float softShadow_sampleTaps( sampler2D shadowMap, diff --git a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl index 1f1c8e140..33c7f333e 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl @@ -27,7 +27,7 @@ #include "../../lighting.hlsl" #include "../shadowMap/shadowMapIO_HLSL.h" #include "softShadow.hlsl" - +#include "../../torque.hlsl" struct ConvexConnectP { @@ -39,7 +39,7 @@ struct ConvexConnectP #ifdef USE_COOKIE_TEX /// The texture for cookie rendering. -uniform sampler2D cookieMap : register(S2); +uniform sampler2D cookieMap : register(S3); #endif @@ -48,6 +48,7 @@ float4 main( ConvexConnectP IN, uniform sampler2D prePassBuffer : register(S0), uniform sampler2D shadowMap : register(S1), + uniform sampler2D dynamicShadowMap : register(S2), uniform float4 rtParams0, @@ -62,6 +63,7 @@ float4 main( ConvexConnectP IN, uniform float4 vsFarPlane, uniform float4x4 viewToLightProj, + uniform float4x4 dynamicViewToLightProj, uniform float4 lightParams, uniform float shadowSoftness ) : COLOR0 @@ -101,6 +103,11 @@ float4 main( ConvexConnectP IN, float2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); shadowCoord.y = 1.0f - shadowCoord.y; + // Get the dynamic shadow texture coordinate + float4 dynpxlPosLightProj = mul( dynamicViewToLightProj, float4( viewSpacePos, 1 ) ); + float2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; + #ifdef NO_SHADOW float shadowed = 1.0; @@ -110,14 +117,22 @@ float4 main( ConvexConnectP IN, // Get a linear depth from the light source. float distToLight = pxlPosLightProj.z / lightRange; - float shadowed = softShadow_filter( shadowMap, + float static_shadowed = softShadow_filter( shadowMap, ssPos.xy, shadowCoord, shadowSoftness, distToLight, nDotL, lightParams.y ); - + + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); #endif // !NO_SHADOW float3 lightcol = lightColor.rgb; diff --git a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl index 266cc6438..1b4548575 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl @@ -30,68 +30,31 @@ #include "softShadow.hlsl" -uniform sampler2D ShadowMap : register(S1); +uniform sampler2D shadowMap : register(S1); +uniform sampler2D dynamicShadowMap : register(S2); #ifdef USE_SSAO_MASK -uniform sampler2D ssaoMask : register(S2); +uniform sampler2D ssaoMask : register(S3); uniform float4 rtParams2; #endif - -float4 main( FarFrustumQuadConnectP IN, - - uniform sampler2D prePassBuffer : register(S0), - - uniform float3 lightDirection, - uniform float4 lightColor, - uniform float lightBrightness, - uniform float4 lightAmbient, - - uniform float3 eyePosWorld, - - uniform float4x4 worldToLightProj, - - uniform float4 scaleX, - uniform float4 scaleY, - uniform float4 offsetX, - uniform float4 offsetY, - uniform float4 atlasXOffset, - uniform float4 atlasYOffset, - uniform float2 atlasScale, - uniform float4 zNearFarInvNearFar, - uniform float4 lightMapParams, - - uniform float2 fadeStartLength, - uniform float4 farPlaneScalePSSM, - uniform float4 overDarkPSSM, - uniform float shadowSoftness ) : COLOR0 +float4 AL_VectorLightShadowCast( sampler2D sourceShadowMap, + float2 texCoord, + float4x4 worldToLightProj, + float4 worldPos, + float4 scaleX, + float4 scaleY, + float4 offsetX, + float4 offsetY, + float4 farPlaneScalePSSM, + float4 atlasXOffset, + float4 atlasYOffset, + float2 atlasScale, + float shadowSoftness, + float dotNL , + float4 overDarkPSSM +) { - // Sample/unpack the normal/z data - float4 prepassSample = prepassUncondition( prePassBuffer, IN.uv0 ); - float3 normal = prepassSample.rgb; - float depth = prepassSample.a; - - // Use eye ray to get ws pos - float4 worldPos = float4(eyePosWorld + IN.wsEyeRay * depth, 1.0f); - - // Get the light attenuation. - float dotNL = dot(-lightDirection, normal); - - #ifdef PSSM_DEBUG_RENDER - float3 debugColor = 0; - #endif - - #ifdef NO_SHADOW - - // Fully unshadowed. - float shadowed = 1.0; - - #ifdef PSSM_DEBUG_RENDER - debugColor = 1.0; - #endif - - #else - // Compute shadow map coordinate float4 pxlPosLightProj = mul(worldToLightProj, worldPos); float2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; @@ -132,6 +95,11 @@ float4 main( FarFrustumQuadConnectP IN, else finalMask = float4(0, 0, 0, 1); + float3 debugColor = float3(0,0,0); + + #ifdef NO_SHADOW + debugColor = float3(1.0,1.0,1.0); + #endif #ifdef PSSM_DEBUG_RENDER if ( finalMask.x > 0 ) @@ -174,19 +142,125 @@ float4 main( FarFrustumQuadConnectP IN, // Each split has a different far plane, take this into account. float farPlaneScale = dot( farPlaneScalePSSM, finalMask ); distToLight *= farPlaneScale; + + return float4(debugColor, + softShadow_filter( sourceShadowMap, + texCoord, + shadowCoord, + farPlaneScale * shadowSoftness, + distToLight, + dotNL, + dot( finalMask, overDarkPSSM ) ) ); +}; + +float4 main( FarFrustumQuadConnectP IN, + + uniform sampler2D prePassBuffer : register(S0), + + uniform float3 lightDirection, + uniform float4 lightColor, + uniform float lightBrightness, + uniform float4 lightAmbient, + uniform float4x4 eyeMat, + + uniform float3 eyePosWorld, + uniform float4 atlasXOffset, + uniform float4 atlasYOffset, + uniform float2 atlasScale, + uniform float4 zNearFarInvNearFar, + uniform float4 lightMapParams, + uniform float2 fadeStartLength, + uniform float4 overDarkPSSM, + uniform float shadowSoftness, + + // Static Shadows + uniform float4x4 worldToLightProj, + uniform float4 scaleX, + uniform float4 scaleY, + uniform float4 offsetX, + uniform float4 offsetY, + uniform float4 farPlaneScalePSSM, + + // Dynamic Shadows + uniform float4x4 dynamicWorldToLightProj, + uniform float4 dynamicScaleX, + uniform float4 dynamicScaleY, + uniform float4 dynamicOffsetX, + uniform float4 dynamicOffsetY, + uniform float4 dynamicFarPlaneScalePSSM + + ) : COLOR0 +{ + // Sample/unpack the normal/z data + float4 prepassSample = prepassUncondition( prePassBuffer, IN.uv0 ); + float3 normal = prepassSample.rgb; + float depth = prepassSample.a; + + // Use eye ray to get ws pos + float4 worldPos = float4(eyePosWorld + IN.wsEyeRay * depth, 1.0f); + + // Get the light attenuation. + float dotNL = dot(-lightDirection, normal); + + #ifdef PSSM_DEBUG_RENDER + float3 debugColor = float3(0,0,0); + #endif + + #ifdef NO_SHADOW + + // Fully unshadowed. + float shadowed = 1.0; + + #ifdef PSSM_DEBUG_RENDER + debugColor = float3(1.0,1.0,1.0); + #endif + + #else - float shadowed = softShadow_filter( ShadowMap, - IN.uv0.xy, - shadowCoord, - farPlaneScale * shadowSoftness, - distToLight, - dotNL, - dot( finalMask, overDarkPSSM ) ); + float4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap, + IN.uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + + float4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap, + IN.uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + + #ifdef PSSM_DEBUG_RENDER + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; + #endif // Fade out the shadow at the end of the range. float4 zDist = (zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; - shadowed = lerp( shadowed, 1.0, saturate( fadeOutAmt ) ); + + static_shadowed = lerp( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = lerp( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); #ifdef PSSM_DEBUG_RENDER if ( fadeOutAmt > 1.0 ) diff --git a/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui b/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui index b4b006904..2062f43f3 100644 --- a/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui +++ b/Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui @@ -3309,7 +3309,7 @@ HorizSizing = "width"; VertSizing = "bottom"; Position = "0 0"; - Extent = "210 71"; + Extent = "210 89"; new GuiPopUpMenuCtrl() { internalName = "blendingTypePopUp"; @@ -3480,7 +3480,7 @@ Visible = "1"; Command = "MaterialEditorGui.updateActiveMaterial(\"castShadows\", $ThisControl.getValue());"; tooltipprofile = "ToolsGuiDefaultProfile"; - ToolTip = "Alows object to cast shadows."; + ToolTip = "Object casts shadows."; hovertime = "1000"; text = "Cast Shadows"; groupNum = "-1"; @@ -3488,6 +3488,29 @@ useMouseEvents = "0"; useInactiveState = "0"; }; + new GuiCheckBoxCtrl() { + canSaveDynamicFields = "0"; + internalName = "castDynamicShadows"; + Enabled = "1"; + isContainer = "0"; + Profile = "ToolsGuiCheckBoxProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + position = "3 70"; + Extent = "112 16"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + Command = "MaterialEditorGui.updateActiveMaterial(\"castDynamicShadows\", $ThisControl.getValue());"; + tooltipprofile = "ToolsGuiDefaultProfile"; + ToolTip = "Object casts dynamic shadows."; + hovertime = "1000"; + text = "Dynamic Shadows"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + useInactiveState = "0"; + }; new GuiCheckBoxCtrl() { canSaveDynamicFields = "0"; internalName = "doubleSidedCheckBox"; diff --git a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs index 6b055d05c..be7d55c39 100644 --- a/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs +++ b/Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs @@ -754,6 +754,7 @@ function MaterialEditorGui::guiSync( %this, %material ) MaterialEditorPropertiesWindow-->transZWriteCheckBox.setValue((%material).translucentZWrite); MaterialEditorPropertiesWindow-->alphaTestCheckBox.setValue((%material).alphaTest); MaterialEditorPropertiesWindow-->castShadows.setValue((%material).castShadows); + MaterialEditorPropertiesWindow-->castDynamicShadows.setValue((%material).castDynamicShadows); MaterialEditorPropertiesWindow-->translucentCheckbox.setValue((%material).translucent); switch$((%material).translucentBlendOp)