Browse Source

shadow caching

SPECIAL NOTE: highly suggest https://github.com/GarageGames/Torque3D/pull/1441 or a variation thereof to prevent debug spew and false-postives for occlusion results.

With significant research, development and prototyping assistance from both @andr3wmac (shaders and partial hook work), and @LuisAntonRebollo (additional culling)

System operates as follows:
1) materials are given an additional castDynamicShadows boolean entry. (Default at time of writing is true by request. Personal usage at time of writing defaults to false. value is default-initialized in materialDefinition.cpp. script/gui exposed)
2) lights are given a staticRefreshFreq and dynamicRefreshFreq (in milliseconds). script/gui exposed
3) materials are (effectively) sorted into dynamic and static shadowmap render lists based on flag. (see shadowMapPass.cpp)
4) initial shadowmaps are generated for each light and 'list'.
5) as each refreshFreq times out, the relevant shadowmap for a given light is refreshed.

Special notes:
dynamicRefreshFreq for all lights is set to a (script exposed) 8MS refresh timer.
StaticRefreshFreq for the lions share of lights defaults to 250 MS (1/4 of a second)
scattersky's embedded light, which is intended to operate in a mobile manner, defaults to 8
to reiterate, these are all customizable per-light via script/inspector gui in the case of alternate project needs.
Azaezel 10 years ago
parent
commit
2753f562e8
54 changed files with 1403 additions and 390 deletions
  1. 8 0
      Engine/source/T3D/lightBase.cpp
  2. 2 1
      Engine/source/T3D/lightBase.h
  3. 10 0
      Engine/source/T3D/lightDescription.cpp
  4. 2 0
      Engine/source/T3D/lightDescription.h
  5. 2 0
      Engine/source/T3D/pointLight.cpp
  6. 2 0
      Engine/source/T3D/spotLight.cpp
  7. 11 0
      Engine/source/environment/scatterSky.cpp
  8. 2 0
      Engine/source/environment/scatterSky.h
  9. 13 2
      Engine/source/environment/sun.cpp
  10. 2 0
      Engine/source/environment/sun.h
  11. 3 0
      Engine/source/forest/forestCell.cpp
  12. 4 0
      Engine/source/forest/forestRender.cpp
  13. 7 1
      Engine/source/lighting/advanced/advancedLightBinManager.cpp
  14. 1 0
      Engine/source/lighting/advanced/advancedLightBinManager.h
  15. 63 7
      Engine/source/lighting/advanced/advancedLightManager.cpp
  16. 4 0
      Engine/source/lighting/lightInfo.cpp
  17. 9 0
      Engine/source/lighting/lightInfo.h
  18. 89 31
      Engine/source/lighting/shadowMap/lightShadowMap.cpp
  19. 37 12
      Engine/source/lighting/shadowMap/lightShadowMap.h
  20. 139 6
      Engine/source/lighting/shadowMap/pssmLightShadowMap.cpp
  21. 1 0
      Engine/source/lighting/shadowMap/pssmLightShadowMap.h
  22. 7 0
      Engine/source/lighting/shadowMap/shadowMapManager.cpp
  23. 3 0
      Engine/source/lighting/shadowMap/shadowMapManager.h
  24. 77 17
      Engine/source/lighting/shadowMap/shadowMapPass.cpp
  25. 17 0
      Engine/source/lighting/shadowMap/shadowMapPass.h
  26. 1 0
      Engine/source/materials/baseMaterialDefinition.h
  27. 5 1
      Engine/source/materials/materialDefinition.cpp
  28. 4 1
      Engine/source/materials/materialDefinition.h
  29. 8 0
      Engine/source/materials/processedCustomMaterial.cpp
  30. 8 0
      Engine/source/math/mPoint2.h
  31. 51 0
      Engine/source/math/mathUtils.cpp
  32. 3 0
      Engine/source/math/mathUtils.h
  33. 5 0
      Engine/source/scene/culling/sceneCullingState.cpp
  34. 18 0
      Engine/source/scene/culling/sceneCullingState.h
  35. 14 8
      Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs
  36. 18 4
      Templates/Empty/game/shaders/common/lighting/advanced/gl/pointLightP.glsl
  37. 20 4
      Templates/Empty/game/shaders/common/lighting/advanced/gl/spotLightP.glsl
  38. 138 64
      Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl
  39. 22 7
      Templates/Empty/game/shaders/common/lighting/advanced/pointLightP.hlsl
  40. 1 1
      Templates/Empty/game/shaders/common/lighting/advanced/softShadow.hlsl
  41. 22 6
      Templates/Empty/game/shaders/common/lighting/advanced/spotLightP.hlsl
  42. 138 64
      Templates/Empty/game/shaders/common/lighting/advanced/vectorLightP.hlsl
  43. 25 2
      Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  44. 1 0
      Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs
  45. 14 8
      Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs
  46. 14 1
      Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl
  47. 17 2
      Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl
  48. 138 64
      Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl
  49. 19 5
      Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl
  50. 1 1
      Templates/Full/game/shaders/common/lighting/advanced/softShadow.hlsl
  51. 19 4
      Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl
  52. 138 64
      Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl
  53. 25 2
      Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  54. 1 0
      Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs

+ 8 - 0
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 );      
       

+ 2 - 1
Engine/source/T3D/lightBase.h

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

+ 10 - 0
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 )

+ 2 - 0
Engine/source/T3D/lightDescription.h

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

+ 2 - 0
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.

+ 2 - 0
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 );

+ 11 - 0
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 );
 

+ 2 - 0
Engine/source/environment/scatterSky.h

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

+ 13 - 2
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()

+ 2 - 0
Engine/source/environment/sun.h

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

+ 3 - 0
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();
    }

+ 4 - 0
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.

+ 7 - 1
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<ShadowMapParams>();
    LightShadowMap *lsm = lsp->getShadowMap();
+   LightShadowMap *dynamicShadowMap = lsp->getShadowMap(true);
 
    // Get the right shadow type.
    ShadowType shadowType = ShadowType_None;
-   if (  light->getCastShadows() && 
+   if (  light->getCastShadows() &&  
          lsm && lsm->hasShadowTex() &&
          !ShadowMapPass::smDisableShadows )
       shadowType = lsm->getShadowType();
@@ -203,6 +204,7 @@ void AdvancedLightBinManager::addLight( LightInfo *light )
    LightBinEntry lEntry;
    lEntry.lightInfo = light;
    lEntry.shadowMap = lsm;
+   lEntry.dynamicShadowMap = dynamicShadowMap;
    lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() );
 
    if( lightType == LightInfo::Spot )
@@ -325,10 +327,12 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
       setupSGData( sgData, state, curLightInfo );
       curLightMat->setLightParameters( curLightInfo, state, worldToCameraXfm );
       mShadowManager->setLightShadowMap( curEntry.shadowMap );
+      mShadowManager->setLightDynamicShadowMap( curEntry.dynamicShadowMap );
 
       // Let the shadow know we're about to render from it.
       if ( curEntry.shadowMap )
          curEntry.shadowMap->preLightRender();
+      if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->preLightRender();
 
       // Set geometry
       GFX->setVertexBuffer( curEntry.vertBuffer );
@@ -351,10 +355,12 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
       // Tell it we're done rendering.
       if ( curEntry.shadowMap )
          curEntry.shadowMap->postLightRender();
+      if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->postLightRender();
    }
 
    // Set NULL for active shadow map (so nothing gets confused)
    mShadowManager->setLightShadowMap(NULL);
+   mShadowManager->setLightDynamicShadowMap(NULL);
    GFX->setVertexBuffer( NULL );
    GFX->setPrimitiveBuffer( NULL );
 

+ 1 - 0
Engine/source/lighting/advanced/advancedLightBinManager.h

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

+ 63 - 7
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 )

+ 4 - 0
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++ )
    {

+ 9 - 0
Engine/source/lighting/lightInfo.h

@@ -131,6 +131,9 @@ protected:
 
    bool mCastShadows;
 
+   S32 mStaticRefreshFreq;
+   S32 mDynamicRefreshFreq;
+
    ::Vector<LightInfoEx*> mExtended;
 
    /// The priority of this light used for
@@ -190,6 +193,12 @@ public:
 
    bool getCastShadows() const { return mCastShadows; }
    void setCastShadows( bool castShadows ) { mCastShadows = castShadows; }
+   
+   S32 getStaticRefreshFreq() const { return mStaticRefreshFreq; }
+   void setStaticRefreshFreq(S32 _staticRefreshFreq) { mStaticRefreshFreq = _staticRefreshFreq; }
+
+   S32 getDynamicRefreshFreq() const { return mDynamicRefreshFreq; }
+   void setDynamicRefreshFreq(S32 _dynamicRefreshFreq) { mDynamicRefreshFreq = _dynamicRefreshFreq; }
 
    void setPriority( F32 priority ) { mPriority = priority; }
    F32 getPriority() const { return mPriority; }

+ 89 - 31
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");
+   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");
-   mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset");
-   mAtlasYOffsetSC = shader->getShaderConstHandle("$atlasYOffset");
-   mAtlasScaleSC = shader->getShaderConstHandle("$atlasScale");
-
-   mFadeStartLength = shader->getShaderConstHandle("$fadeStartLength");
    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 );

+ 37 - 12
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_

+ 139 - 6
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<PlaneF> > _extraCull;
+   _calcPlanesCullForShadowCasters( _extraCull, fullFrustum, mLight->getDirection() );
+
    for (U32 i = 0; i < mNumSplits; i++)
    {
       GFXTransformSaver saver;
@@ -365,12 +369,17 @@ void PSSMLightShadowMap::_render(   RenderPassManager* renderPass,
       shadowRenderState.setDiffuseCameraTransform( diffuseState->getCameraTransform() );
       shadowRenderState.setWorldToScreenScale( diffuseState->getWorldToScreenScale() );
 
+      PlaneSetF planeSet( _extraCull[i].address(), _extraCull[i].size() );
+      shadowRenderState.getCullingState().setExtraPlanesCull( planeSet );
+
       U32 objectMask = SHADOW_TYPEMASK;
       if ( i == mNumSplits-1 && params->lastSplitTerrainOnly )
          objectMask = TerrainObjectType;
 
       sceneManager->renderSceneNoLights( &shadowRenderState, objectMask );
 
+      shadowRenderState.getCullingState().clearExtraPlanesCull();
+
       _debugRender( &shadowRenderState );
    }
 
@@ -435,18 +444,28 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
       }
    }
 
-   params->setSafe(lsc->mScaleXSC, sx);
-   params->setSafe(lsc->mScaleYSC, sy);
-   params->setSafe(lsc->mOffsetXSC, ox);
-   params->setSafe(lsc->mOffsetYSC, oy);
+   // These values change based on static/dynamic.
+   if ( mIsDynamic )
+   {
+      params->setSafe(lsc->mDynamicScaleXSC, sx);
+      params->setSafe(lsc->mDynamicScaleYSC, sy);
+      params->setSafe(lsc->mDynamicOffsetXSC, ox);
+      params->setSafe(lsc->mDynamicOffsetYSC, oy);
+      params->setSafe( lsc->mDynamicFarPlaneScalePSSM, mFarPlaneScalePSSM);
+   } else {
+      params->setSafe(lsc->mScaleXSC, sx);
+      params->setSafe(lsc->mScaleYSC, sy);
+      params->setSafe(lsc->mOffsetXSC, ox);
+      params->setSafe(lsc->mOffsetYSC, oy);
+      params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
+   }
+
    params->setSafe(lsc->mAtlasXOffsetSC, aXOff);
    params->setSafe(lsc->mAtlasYOffsetSC, aYOff);
    params->setSafe(lsc->mAtlasScaleSC, shadowMapAtlas);
 
    Point4F lightParams( mLight->getRange().x, p->overDarkFactor.x, 0.0f, 0.0f );
    params->setSafe( lsc->mLightParamsSC, lightParams );
-      
-   params->setSafe( lsc->mFarPlaneScalePSSM, mFarPlaneScalePSSM);
 
    Point2F fadeStartLength(p->fadeStartDist, 0.0f);
    if (fadeStartLength.x == 0.0f)
@@ -462,3 +481,117 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
    // The softness is a factor of the texel size.
    params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
 }
+
+void PSSMLightShadowMap::_calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir)
+{
+
+#define ENABLE_CULL_ASSERT
+
+   PROFILE_SCOPE(PSSMLightShadowMap_render_getCullFrustrum);
+
+   Point3F ligthDir = _ligthDir;
+   PlaneF lightFarPlane, lightNearPlane;
+   MatrixF lightFarPlaneMat(true);
+   MatrixF invLightFarPlaneMat(true);
+
+   // init data
+   {
+      ligthDir.normalize();
+      Point3F viewDir = viewFrustum.getTransform().getForwardVector();
+      viewDir.normalize();
+      const Point3F viewPosition = viewFrustum.getPosition();
+      const F32 viewDistance = viewFrustum.getBounds().len();
+      lightNearPlane = PlaneF(viewPosition + (viewDistance * -ligthDir), ligthDir);
+
+      const Point3F lightFarPlanePos = viewPosition + (viewDistance * ligthDir);
+      lightFarPlane = PlaneF(lightFarPlanePos, -ligthDir);
+
+      lightFarPlaneMat = MathUtils::createOrientFromDir(-ligthDir);
+      lightFarPlaneMat.setPosition(lightFarPlanePos);
+      lightFarPlaneMat.invertTo(&invLightFarPlaneMat);
+   }
+
+   Vector<Point2F> projVertices;
+
+   //project all frustum vertices into plane
+   // all vertices are 2d and local to far plane
+   projVertices.setSize(8);
+   for (int i = 0; i < 8; ++i) //
+   {
+      const Point3F &point = viewFrustum.getPoints()[i];
+#ifdef ENABLE_CULL_ASSERT
+      AssertFatal( PlaneF::Front == lightNearPlane.whichSide(point), "" );
+      AssertFatal( PlaneF::Front == lightFarPlane.whichSide(point), "" );
+#endif
+
+      Point3F localPoint(lightFarPlane.project(point));
+      invLightFarPlaneMat.mulP(localPoint);
+      projVertices[i] = Point2F(localPoint.x, localPoint.z);
+   }
+
+   //create hull arround projected proints
+   Vector<Point2F> hullVerts;
+   MathUtils::mBuildHull2D(projVertices, hullVerts);
+
+   Vector<PlaneF> planes;
+   planes.push_back(lightNearPlane);
+   planes.push_back(lightFarPlane);
+
+   //build planes
+   for (int i = 0; i < (hullVerts.size() - 1); ++i)
+   {
+      Point2F pos2D = (hullVerts[i] + hullVerts[i + 1]) / 2;
+      Point3F pos3D(pos2D.x, 0, pos2D.y);
+
+      Point3F pos3DA(hullVerts[i].x, 0, hullVerts[i].y);
+      Point3F pos3DB(hullVerts[i + 1].x, 0, hullVerts[i + 1].y);
+
+      // move hull points to 3d space
+      lightFarPlaneMat.mulP(pos3D);
+      lightFarPlaneMat.mulP(pos3DA);
+      lightFarPlaneMat.mulP(pos3DB);
+
+      PlaneF plane(pos3D, MathUtils::mTriangleNormal(pos3DB, pos3DA, (pos3DA - ligthDir)));
+      planes.push_back(plane);
+   }
+
+   //recalculate planes for each splits
+   for (int split = 0; split < mNumSplits; ++split)
+   {
+      Frustum subFrustum(viewFrustum);
+      subFrustum.cropNearFar(mSplitDist[split], mSplitDist[split + 1]);
+      subFrustum.setFarDist(getMin(subFrustum.getFarDist()*2.5f, viewFrustum.getFarDist()));
+      subFrustum.update();
+
+      Vector<PlaneF> subPlanes = planes;
+
+      for (int planeIdx = 0; planeIdx < subPlanes.size(); ++planeIdx)
+      {
+         PlaneF &plane = subPlanes[planeIdx];
+         F32 minDist = 0;
+
+         //calculate near vertex distance
+         for (int vertexIdx = 0; vertexIdx < 8; ++vertexIdx)
+         {
+            Point3F point = subFrustum.getPoints()[vertexIdx];
+            minDist = getMin(plane.distToPlane(point), minDist);
+         }
+
+         // move plane to near vertex
+         Point3F newPos = plane.getPosition() + (plane.getNormal() * minDist);
+         plane = PlaneF(newPos, plane.getNormal());
+
+#ifdef ENABLE_CULL_ASSERT
+         for(int x = 0; x < 8; ++x)
+         {
+            AssertFatal( PlaneF::Back != plane.whichSide( subFrustum.getPoints()[x] ), "");
+         }
+#endif
+      }
+
+      out.push_back(subPlanes);
+   }
+
+#undef ENABLE_CULL_ASSERT
+
+}

+ 1 - 0
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<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir);
    void _roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum);
 
    static const S32 MAX_SPLITS = 4;

+ 7 - 0
Engine/source/lighting/shadowMap/shadowMapManager.cpp

@@ -86,6 +86,7 @@ Signal<void(void)> ShadowMapManager::smShadowDeactivateSignal;
 ShadowMapManager::ShadowMapManager() 
 :  mShadowMapPass(NULL), 
    mCurrentShadowMap(NULL),
+   mCurrentDynamicShadowMap(NULL),
    mIsActive(false)
 {
 }
@@ -98,9 +99,15 @@ void ShadowMapManager::setLightShadowMapForLight( LightInfo *light )
 {
    ShadowMapParams *params = light->getExtended<ShadowMapParams>();
    if ( params )
+   {
       mCurrentShadowMap = params->getShadowMap();
+      mCurrentDynamicShadowMap = params->getShadowMap(true);
+   }
    else 
+   {
       mCurrentShadowMap = NULL;
+      mCurrentDynamicShadowMap = NULL;
+   }
 }
 
 void ShadowMapManager::activate()

+ 3 - 0
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;

+ 77 - 17
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<LightShadowMap*> shadowMaps;
-   shadowMaps.reserve( mActiveLights );
+   shadowMaps.reserve( mActiveLights * 2 );
    for ( U32 i = 0; i < mActiveLights; i++ )
    {
       ShadowMapParams *params = mLights[i]->getExtended<ShadowMapParams>();
@@ -155,12 +172,14 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
       // Before we do anything... skip lights without shadows.      
       if ( !mLights[i]->getCastShadows() || smDisableShadows )
          continue;
-
-      LightShadowMap *lsm = params->getOrCreateShadowMap();
+      
+      // --- Static Shadow Map ---
+	  LightShadowMap *lsm = params->getOrCreateShadowMap();
+     LightShadowMap *dlsm = params->getOrCreateShadowMap(true);
 
       // First check the visiblity query... if it wasn't 
       // visible skip it.
-      if ( lsm->wasOccluded() )
+     if (lsm->wasOccluded() || dlsm->wasOccluded())
          continue;
 
       // Any shadow that is visible is counted as being 
@@ -168,13 +187,25 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
       ++smActiveShadowMaps;
 
       // Do a priority update for this shadow.
-      lsm->updatePriority( diffuseState, currTime );
+	  lsm->updatePriority(diffuseState, currTime);
+
+	  shadowMaps.push_back(lsm);
+
+      // --- Dynamic Shadow Map ---
 
-      shadowMaps.push_back( lsm );
+      // Any shadow that is visible is counted as being 
+      // active regardless if we update it or not.
+      ++smActiveShadowMaps;
+
+      // Do a priority update for this shadow.
+	  dlsm->updatePriority(diffuseState, currTime);
+
+      shadowMaps.push_back( dlsm );
    }
 
    // Now sort the shadow info by priority.
-   shadowMaps.sort( LightShadowMap::cmpPriority );
+   // andrewmac: tempoarily disabled until I find a better solution.
+   //shadowMaps.sort( LightShadowMap::cmpPriority );
 
    GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render, ColorI::RED );
 
@@ -183,22 +214,28 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
    mTimer->getElapsedMs();
    mTimer->reset();
 
-   for ( U32 i = 0; i < shadowMaps.size(); i++ )
+   // 2 Shadow Maps per Light. This may fail.
+   for ( U32 i = 0; i < shadowMaps.size(); i += 2 )
    {
-      LightShadowMap *lsm = shadowMaps[i];
+	   LightShadowMap *lsm = shadowMaps[i];
+	   LightShadowMap *dlsm = shadowMaps[i + 1];
 
       {
          GFXDEBUGEVENT_SCOPE( ShadowMapPass_Render_Shadow, ColorI::RED );
 
-         mShadowManager->setLightShadowMap( lsm );
-         lsm->render( mShadowRPM, diffuseState );
+		 mShadowManager->setLightShadowMap(lsm);
+         mShadowManager->setLightDynamicShadowMap( dlsm );
+
+		 lsm->render(mShadowRPM, diffuseState, false);
+		 dlsm->render(mDynamicShadowRPM, diffuseState, true);
+
          ++smUpdatedShadowMaps;
       }
 
       // View dependent shadows or ones that are covering the entire
       // screen are updated every frame no matter the time left in
       // our shadow rendering budget.
-      if ( lsm->isViewDependent() || lsm->getLastScreenSize() >= 1.0f )
+      if ( dlsm->isViewDependent() || dlsm->getLastScreenSize() >= 1.0f )
       {
          ++smNearShadowMaps;
          continue;
@@ -224,6 +261,7 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
    // The NULL here is importaint as having it around
    // will cause extra work in AdvancedLightManager::setLightInfo().
    mShadowManager->setLightShadowMap( NULL );
+   mShadowManager->setLightDynamicShadowMap( NULL );
 }
 
 void ShadowRenderPassManager::addInst( RenderInst *inst )
@@ -237,7 +275,29 @@ void ShadowRenderPassManager::addInst( RenderInst *inst )
          return;
 
       const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
-      if ( !mat->castsShadows() || mat->isTranslucent() )
+      if ( !mat->castsShadows() || mat->castsDynamicShadows() || mat->isTranslucent() )
+      {
+         // Do not add this instance, return here and avoid the default behavior
+         // of calling up to Parent::addInst()
+         return;
+      }
+   }
+
+   Parent::addInst(inst);
+}
+
+void DynamicShadowRenderPassManager::addInst( RenderInst *inst )
+{
+   PROFILE_SCOPE(DynamicShadowRenderPassManager_addInst);
+
+   if ( inst->type == RIT_Mesh )
+   {
+      MeshRenderInst *meshRI = static_cast<MeshRenderInst*>( inst );
+      if ( !meshRI->matInst )
+         return;
+
+      const BaseMaterialDefinition *mat = meshRI->matInst->getMaterial();
+      if ( !mat->castsShadows() || !mat->castsDynamicShadows() || mat->isTranslucent() )
       {
          // Do not add this instance, return here and avoid the default behavior
          // of calling up to Parent::addInst()

+ 17 - 0
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<ShadowRenderPassManager> mShadowRPM;
+   SimObjectPtr<DynamicShadowRenderPassManager> mDynamicShadowRPM;
    LightManager* mLightManager;
    ShadowMapManager* mShadowManager;
 };
@@ -117,4 +124,14 @@ public:
    virtual void addInst( RenderInst *inst );
 };
 
+class DynamicShadowRenderPassManager : public RenderPassManager
+{
+	typedef RenderPassManager Parent;
+public:
+	DynamicShadowRenderPassManager() : Parent() {}
+
+	/// Add a RenderInstance to the list
+	virtual void addInst(RenderInst *inst);
+};
+
 #endif // _SHADOWMAPPASS_H_

+ 1 - 0
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_

+ 5 - 1
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),

+ 4 - 1
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();

+ 8 - 0
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;

+ 8 - 0
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
 {

+ 51 - 0
Engine/source/math/mathUtils.cpp

@@ -1845,4 +1845,55 @@ U32 extrudePolygonEdgesFromPoint( const Point3F* vertices, U32 numVertices, cons
    return numPlanes;
 }
 
+//-----------------------------------------------------------------------------
+
+void MathUtils::mBuildHull2D(const Vector<Point2F> _inPoints, Vector<Point2F> &hullPoints)
+{
+   /// Andrew's monotone chain convex hull algorithm implementation
+
+   struct Util
+   {
+      //compare by x and then by y   
+      static int CompareLexicographic( const Point2F *a, const Point2F *b)
+      {
+         return a->x < b->x || (a->x == b->x && a->y < b->y);
+      }
+   };
+
+   hullPoints.clear();
+   hullPoints.setSize( _inPoints.size()*2 );
+
+   // sort in points by x and then by y
+   Vector<Point2F> inSortedPoints = _inPoints;
+   inSortedPoints.sort( &Util::CompareLexicographic );
+
+   Point2F* lowerHullPtr = hullPoints.address();
+   U32 lowerHullIdx = 0;
+
+   //lower part of hull
+   for( int i = 0; i < inSortedPoints.size(); ++i )
+   {      
+      while( lowerHullIdx >= 2 && mCross( lowerHullPtr[ lowerHullIdx - 2], lowerHullPtr[lowerHullIdx - 1], inSortedPoints[i] ) <= 0 )
+         --lowerHullIdx;
+
+      lowerHullPtr[lowerHullIdx++] = inSortedPoints[i];
+   }
+
+   --lowerHullIdx; // last point are the same as first in upperHullPtr
+
+   Point2F* upperHullPtr = hullPoints.address() + lowerHullIdx;
+   U32 upperHullIdx = 0;
+
+   //upper part of hull
+   for( int i = inSortedPoints.size()-1; i >= 0; --i )
+   {
+      while( upperHullIdx >= 2 && mCross( upperHullPtr[ upperHullIdx - 2], upperHullPtr[upperHullIdx - 1], inSortedPoints[i] ) <= 0 )
+         --upperHullIdx;
+
+      upperHullPtr[upperHullIdx++] = inSortedPoints[i];
+   }
+
+   hullPoints.setSize( lowerHullIdx + upperHullIdx );
+}
+
 } // namespace MathUtils

+ 3 - 0
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<Point2F> inPoints, Vector<Point2F> &hullPoints);
+
 } // namespace MathUtils
 
 #endif // _MATHUTILS_H_

+ 5 - 0
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;
    }

+ 18 - 0
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;

+ 14 - 8
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";

+ 18 - 4
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

+ 20 - 4
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

+ 138 - 64
Templates/Empty/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl

@@ -34,81 +34,78 @@ 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;
-
-out vec4 OUT_col;
-
-void main()             
-{
-   // Sample/unpack the normal/z data
-   vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 );
-   vec3 normal = prepassSample.rgb;
-   float depth = prepassSample.a;
-
-   // Use eye ray to get ws pos
-   vec4 worldPos = vec4(eyePosWorld + wsEyeRay * depth, 1.0f);
-   
-   // Get the light attenuation.
-   float dotNL = dot(-lightDirection, normal);
-
-   #ifdef PSSM_DEBUG_RENDER
-      vec3 debugColor = vec3(0);
-   #endif
    
-   #ifdef NO_SHADOW
-
-      // Fully unshadowed.
-      float shadowed = 1.0;
+//static shadowMap
+uniform mat4x4 worldToLightProj;
+uniform vec4 scaleX;
+uniform vec4 scaleY;
+uniform vec4 offsetX;
+uniform vec4 offsetY;
+uniform vec4 farPlaneScalePSSM;
 
-      #ifdef PSSM_DEBUG_RENDER
-         debugColor = vec3(1.0);
-      #endif
+//dynamic shadowMap
+uniform mat4x4 dynamicWorldToLightProj;
+uniform vec4 dynamicScaleX;
+uniform vec4 dynamicScaleY;
+uniform vec4 dynamicOffsetX;
+uniform vec4 dynamicOffsetY;
+uniform vec4 dynamicFarPlaneScalePSSM;
 
-   #else
+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);
+      vec4 pxlPosLightProj = tMul(_worldToLightProj, _worldPos);
       vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w;   
 
-      // Distance to light, in shadowmap space
+      // 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
+      // 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;
+      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 
@@ -132,6 +129,11 @@ void main()
       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 )
@@ -144,50 +146,122 @@ void main()
             debugColor += vec3( 1, 1, 0 );
       #endif
 
-      // Here we know what split we're sampling from, so recompute the texcoord location
+      // 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);
+      finalScale.x = dot(finalMask, _scaleX);
+      finalScale.y = dot(finalMask, _scaleY);
 
       vec2 finalOffset;
-      finalOffset.x = dot(finalMask, offsetX);
-      finalOffset.y = dot(finalMask, offsetY);
+      finalOffset.x = dot(finalMask, _offsetX);
+      finalOffset.y = dot(finalMask, _offsetY);
 
       vec2 shadowCoord;                  
       shadowCoord = baseShadowCoord * finalScale;      
       shadowCoord += finalOffset;
 
-      // Convert to texcoord space
+      // 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);
+      aOffset.x = dot(finalMask, _atlasXOffset);
+      aOffset.y = dot(finalMask, _atlasYOffset);
 
-      shadowCoord *= atlasScale;
+      shadowCoord *= _atlasScale;
       shadowCoord += aOffset;
               
       // Each split has a different far plane, take this into account.
-      float farPlaneScale = dot( farPlaneScalePSSM, finalMask );
+      float farPlaneScale = dot( _farPlaneScalePSSM, finalMask );
       distToLight *= farPlaneScale;
       
-      float shadowed = softShadow_filter(   ShadowMap,
-                                             uv0.xy,
-                                             shadowCoord,
-                                             farPlaneScale * shadowSoftness,
-                                             distToLight,
-                                             dotNL,
-                                             dot( finalMask, overDarkPSSM ) );
-  
+      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;
+   float depth = prepassSample.a;
+
+   // Use eye ray to get ws pos
+   vec4 worldPos = vec4(eyePosWorld + wsEyeRay * depth, 1.0f);
+   
+   // Get the light attenuation.
+   float dotNL = dot(-lightDirection, normal);
+
+   #ifdef PSSM_DEBUG_RENDER
+      vec3 debugColor = vec3(0);
+   #endif
+   
+   #ifdef NO_SHADOW
+
+      // Fully unshadowed.
+      float shadowed = 1.0;
+
+      #ifdef PSSM_DEBUG_RENDER
+         debugColor = vec3(1.0);
+      #endif
+
+   #else
+
+      vec4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap,
+                                                        uv0.xy,
+                                                        worldToLightProj,
+                                                        worldPos,
+                                                        scaleX, scaleY,
+                                                        offsetX, offsetY,
+                                                        farPlaneScalePSSM,
+                                                        atlasXOffset, atlasYOffset,
+                                                        atlasScale,
+                                                        shadowSoftness, 
+                                                        dotNL,
+                                                        overDarkPSSM);
+
+                                             
+      vec4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap,
+                                                        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.
       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 );  
    
 }

+ 22 - 7
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

+ 1 - 1
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,

+ 22 - 6
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

+ 138 - 64
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
+      
+      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 shadowed = softShadow_filter(   ShadowMap,
-                                             IN.uv0.xy,
-                                             shadowCoord,
-                                             farPlaneScale * shadowSoftness,
-                                             distToLight,
-                                             dotNL,
-                                             dot( finalMask, 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 )

+ 25 - 2
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";

+ 1 - 0
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)

+ 14 - 8
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";

+ 14 - 1
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

+ 17 - 2
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;

+ 138 - 64
Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl

@@ -34,81 +34,78 @@ 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;
-
-out vec4 OUT_col;
-
-void main()             
-{
-   // Sample/unpack the normal/z data
-   vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 );
-   vec3 normal = prepassSample.rgb;
-   float depth = prepassSample.a;
-
-   // Use eye ray to get ws pos
-   vec4 worldPos = vec4(eyePosWorld + wsEyeRay * depth, 1.0f);
-   
-   // Get the light attenuation.
-   float dotNL = dot(-lightDirection, normal);
-
-   #ifdef PSSM_DEBUG_RENDER
-      vec3 debugColor = vec3(0);
-   #endif
    
-   #ifdef NO_SHADOW
-
-      // Fully unshadowed.
-      float shadowed = 1.0;
+//static shadowMap
+uniform mat4x4 worldToLightProj;
+uniform vec4 scaleX;
+uniform vec4 scaleY;
+uniform vec4 offsetX;
+uniform vec4 offsetY;
+uniform vec4 farPlaneScalePSSM;
 
-      #ifdef PSSM_DEBUG_RENDER
-         debugColor = vec3(1.0);
-      #endif
+//dynamic shadowMap
+uniform mat4x4 dynamicWorldToLightProj;
+uniform vec4 dynamicScaleX;
+uniform vec4 dynamicScaleY;
+uniform vec4 dynamicOffsetX;
+uniform vec4 dynamicOffsetY;
+uniform vec4 dynamicFarPlaneScalePSSM;
 
-   #else
+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);
+      vec4 pxlPosLightProj = tMul(_worldToLightProj, _worldPos);
       vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w;   
 
-      // Distance to light, in shadowmap space
+      // 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
+      // 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;
+      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 
@@ -132,6 +129,11 @@ void main()
       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 )
@@ -144,50 +146,122 @@ void main()
             debugColor += vec3( 1, 1, 0 );
       #endif
 
-      // Here we know what split we're sampling from, so recompute the texcoord location
+      // 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);
+      finalScale.x = dot(finalMask, _scaleX);
+      finalScale.y = dot(finalMask, _scaleY);
 
       vec2 finalOffset;
-      finalOffset.x = dot(finalMask, offsetX);
-      finalOffset.y = dot(finalMask, offsetY);
+      finalOffset.x = dot(finalMask, _offsetX);
+      finalOffset.y = dot(finalMask, _offsetY);
 
       vec2 shadowCoord;                  
       shadowCoord = baseShadowCoord * finalScale;      
       shadowCoord += finalOffset;
 
-      // Convert to texcoord space
+      // 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);
+      aOffset.x = dot(finalMask, _atlasXOffset);
+      aOffset.y = dot(finalMask, _atlasYOffset);
 
-      shadowCoord *= atlasScale;
+      shadowCoord *= _atlasScale;
       shadowCoord += aOffset;
               
       // Each split has a different far plane, take this into account.
-      float farPlaneScale = dot( farPlaneScalePSSM, finalMask );
+      float farPlaneScale = dot( _farPlaneScalePSSM, finalMask );
       distToLight *= farPlaneScale;
       
-      float shadowed = softShadow_filter(   ShadowMap,
-                                             uv0.xy,
-                                             shadowCoord,
-                                             farPlaneScale * shadowSoftness,
-                                             distToLight,
-                                             dotNL,
-                                             dot( finalMask, overDarkPSSM ) );
-  
+      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;
+   float depth = prepassSample.a;
+
+   // Use eye ray to get ws pos
+   vec4 worldPos = vec4(eyePosWorld + wsEyeRay * depth, 1.0f);
+   
+   // Get the light attenuation.
+   float dotNL = dot(-lightDirection, normal);
+
+   #ifdef PSSM_DEBUG_RENDER
+      vec3 debugColor = vec3(0);
+   #endif
+   
+   #ifdef NO_SHADOW
+
+      // Fully unshadowed.
+      float shadowed = 1.0;
+
+      #ifdef PSSM_DEBUG_RENDER
+         debugColor = vec3(1.0);
+      #endif
+
+   #else
+
+      vec4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap,
+                                                        uv0.xy,
+                                                        worldToLightProj,
+                                                        worldPos,
+                                                        scaleX, scaleY,
+                                                        offsetX, offsetY,
+                                                        farPlaneScalePSSM,
+                                                        atlasXOffset, atlasYOffset,
+                                                        atlasScale,
+                                                        shadowSoftness, 
+                                                        dotNL,
+                                                        overDarkPSSM);
+
+                                             
+      vec4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap,
+                                                        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.
       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 );  
    
 }

+ 19 - 5
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

+ 1 - 1
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,

+ 19 - 4
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;

+ 138 - 64
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
+      
+      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 shadowed = softShadow_filter(   ShadowMap,
-                                             IN.uv0.xy,
-                                             shadowCoord,
-                                             farPlaneScale * shadowSoftness,
-                                             distToLight,
-                                             dotNL,
-                                             dot( finalMask, 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 )

+ 25 - 2
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";

+ 1 - 0
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)