lightShadowMap.cpp
Engine/source/lighting/shadowMap/lightShadowMap.cpp
Public Variables
Public Functions
GFX_ImplementTextureProfile(ShadowMapProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )
GFX_ImplementTextureProfile(ShadowMapZProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa3a2027753aec009ced4f0818a231296">GFXTextureProfile::ZTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )
Detailed Description
Public Variables
MODULE_END
MODULE_INIT
Public Functions
GFX_ImplementTextureProfile(ShadowMapProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )
GFX_ImplementTextureProfile(ShadowMapZProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa3a2027753aec009ced4f0818a231296">GFXTextureProfile::ZTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "lighting/shadowMap/lightShadowMap.h" 26 27#include "lighting/shadowMap/shadowMapManager.h" 28#include "lighting/shadowMap/shadowMatHook.h" 29#include "gfx/gfxDevice.h" 30#include "gfx/gfxTextureManager.h" 31#include "gfx/gfxOcclusionQuery.h" 32#include "gfx/gfxCardProfile.h" 33#include "gfx/sim/debugDraw.h" 34#include "materials/materialDefinition.h" 35#include "materials/baseMatInstance.h" 36#include "scene/sceneManager.h" 37#include "scene/sceneRenderState.h" 38#include "scene/zones/sceneZoneSpace.h" 39#include "lighting/lightManager.h" 40#include "math/mathUtils.h" 41#include "shaderGen/shaderGenVars.h" 42#include "core/util/safeDelete.h" 43#include "core/stream/bitStream.h" 44#include "math/mathIO.h" 45#include "materials/shaderData.h" 46#include "core/module.h" 47 48// Used for creation in ShadowMapParams::getOrCreateShadowMap() 49#include "lighting/shadowMap/singleLightShadowMap.h" 50#include "lighting/shadowMap/pssmLightShadowMap.h" 51#include "lighting/shadowMap/cubeLightShadowMap.h" 52#include "lighting/shadowMap/dualParaboloidLightShadowMap.h" 53 54// Remove this when the shader constants are reworked better 55#include "lighting/advanced/advancedLightManager.h" 56#include "lighting/advanced/advancedLightBinManager.h" 57 58// TODO: Some cards (Justin's GeForce 7x series) barf on the integer format causing 59// filtering artifacts. These can (sometimes) be resolved by switching the format 60// to FP16 instead of Int16. 61const GFXFormat LightShadowMap::ShadowMapFormat = GFXFormatR32F; // GFXFormatR8G8B8A8; 62 63bool LightShadowMap::smDebugRenderFrustums; 64F32 LightShadowMap::smShadowTexScalar = 1.0f; 65 66Vector<LightShadowMap*> LightShadowMap::smUsedShadowMaps; 67Vector<LightShadowMap*> LightShadowMap::smShadowMaps; 68 69GFX_ImplementTextureProfile( ShadowMapProfile, 70 GFXTextureProfile::DiffuseMap, 71 GFXTextureProfile::PreserveSize | 72 GFXTextureProfile::RenderTarget | 73 GFXTextureProfile::Pooled, 74 GFXTextureProfile::NONE ); 75 76GFX_ImplementTextureProfile( ShadowMapZProfile, 77 GFXTextureProfile::DiffuseMap, 78 GFXTextureProfile::PreserveSize | 79 GFXTextureProfile::NoMipmap | 80 GFXTextureProfile::ZTarget | 81 GFXTextureProfile::Pooled, 82 GFXTextureProfile::NONE ); 83 84 85LightShadowMap::LightShadowMap( LightInfo *light ) 86 : mWorldToLightProj( true ), 87 mTexSize( 0 ), 88 mLight( light ), 89 mLastShader( NULL ), 90 mIsViewDependent( false ), 91 mLastCull( 0 ), 92 mLastScreenSize( 0.0f ), 93 mLastPriority( 0.0f ) 94{ 95 GFXTextureManager::addEventDelegate( this, &LightShadowMap::_onTextureEvent ); 96 97 mTarget = GFX->allocRenderToTextureTarget(); 98 smShadowMaps.push_back( this ); 99} 100 101LightShadowMap::~LightShadowMap() 102{ 103 mTarget = NULL; 104 105 releaseTextures(); 106 107 smShadowMaps.remove( this ); 108 smUsedShadowMaps.remove( this ); 109 110 GFXTextureManager::removeEventDelegate( this, &LightShadowMap::_onTextureEvent ); 111} 112 113void LightShadowMap::releaseAllTextures() 114{ 115 PROFILE_SCOPE( LightShadowMap_ReleaseAllTextures ); 116 117 for ( U32 i=0; i < smShadowMaps.size(); i++ ) 118 smShadowMaps[i]->releaseTextures(); 119} 120 121U32 LightShadowMap::releaseUnusedTextures() 122{ 123 PROFILE_SCOPE( LightShadowMap_ReleaseUnusedTextures ); 124 125 const U32 currTime = Sim::getCurrentTime(); 126 const U32 purgeTime = 1000; 127 128 for ( U32 i=0; i < smUsedShadowMaps.size(); ) 129 { 130 LightShadowMap *lsm = smUsedShadowMaps[i]; 131 132 // If the shadow has not been culled in a while then 133 // release its textures for other shadows to use. 134 if ( currTime > ( lsm->mLastCull + purgeTime ) ) 135 { 136 // Internally this will remove the map from the used 137 // list, so don't increment the loop. 138 lsm->releaseTextures(); 139 continue; 140 } 141 142 i++; 143 } 144 145 return smUsedShadowMaps.size(); 146} 147 148void LightShadowMap::_onTextureEvent( GFXTexCallbackCode code ) 149{ 150 if ( code == GFXZombify ) 151 releaseTextures(); 152 153 // We don't initialize here as we want the textures 154 // to be reallocated when the shadow becomes visible. 155} 156 157void LightShadowMap::calcLightMatrices( MatrixF &outLightMatrix, const Frustum &viewFrustum ) 158{ 159 // Create light matrix, set projection 160 161 switch ( mLight->getType() ) 162 { 163 case LightInfo::Vector : 164 { 165 const ShadowMapParams *p = mLight->getExtended<ShadowMapParams>(); 166 167 // Calculate the bonding box of the shadowed area 168 // we're interested in... this is the shadow box 169 // transformed by the frustum transform. 170 Box3F viewBB( -p->shadowDistance, -p->shadowDistance, -p->shadowDistance, 171 p->shadowDistance, p->shadowDistance, p->shadowDistance ); 172 viewFrustum.getTransform().mul( viewBB ); 173 174 // Calculate a light "projection" matrix. 175 MatrixF lightMatrix = MathUtils::createOrientFromDir(mLight->getDirection()); 176 outLightMatrix = lightMatrix; 177 static MatrixF rotMat(EulerF( (M_PI_F / 2.0f), 0.0f, 0.0f)); 178 lightMatrix.mul( rotMat ); 179 180 // This is the box in lightspace 181 Box3F lightViewBB(viewBB); 182 lightMatrix.mul(lightViewBB); 183 184 // Now, let's position our light based on the lightViewBB 185 Point3F newLightPos(viewBB.getCenter()); 186 F32 sceneDepth = lightViewBB.maxExtents.z - lightViewBB.minExtents.z; 187 newLightPos += mLight->getDirection() * ((-sceneDepth / 2.0f)-1.0f); // -1 for the nearplane 188 outLightMatrix.setPosition(newLightPos); 189 190 // Update light info 191 mLight->setRange( sceneDepth ); 192 mLight->setPosition( newLightPos ); 193 194 // Set our ortho projection 195 F32 width = (lightViewBB.maxExtents.x - lightViewBB.minExtents.x) / 2.0f; 196 F32 height = (lightViewBB.maxExtents.y - lightViewBB.minExtents.y) / 2.0f; 197 198 width = getMax(width, height); 199 200 GFX->setOrtho(-width, width, -width, width, 1.0f, sceneDepth, true); 201 202 203 // TODO: Width * 2... really isn't that pixels being used as 204 // meters? Is a real physical metric of scene depth better? 205 //SceneManager::setVisibleDistance(width * 2.0f); 206 207#if 0 208 LinearColorF(1.0f, 0.0f, 0.0f)); 209 LinearColorF(0.0f, 1.0f, 0.0f)); 210 LinearColorF(0.0f, 0.0f, 1.0f)); 211 LinearColorF(1,1,0)); 212 LinearColorF(0,1,1)); 213 214 a(newLightPos); 215 b(newLightPos); 216 Point3F offset(width, height,0.0f); 217 a -= offset; 218 b += offset; 219 LinearColorF(0.5f, 0.5f, 0.5f)); 220#endif 221 } 222 break; 223 case LightInfo::Spot : 224 { 225 outLightMatrix = mLight->getTransform(); 226 F32 fov = mDegToRad( mLight->getOuterConeAngle() ); 227 F32 farDist = mLight->getRange().x; 228 F32 nearDist = farDist * 0.01f; 229 230 F32 left, right, top, bottom; 231 MathUtils::makeFrustum( &left, &right, &top, &bottom, fov, 1.0f, nearDist ); 232 GFX->setFrustum( left, right, bottom, top, nearDist, farDist ); 233 } 234 break; 235 default: 236 AssertFatal(false, "Unsupported light type!"); 237 } 238} 239 240void LightShadowMap::releaseTextures() 241{ 242 mShadowMapTex = NULL; 243 mDebugTarget.setTexture( NULL ); 244 smUsedShadowMaps.remove( this ); 245} 246 247void LightShadowMap::setDebugTarget( const String &name ) 248{ 249 mDebugTarget.registerWithName( name ); 250 mDebugTarget.setTexture( mShadowMapTex ); 251} 252 253GFXTextureObject* LightShadowMap::_getDepthTarget( U32 width, U32 height ) 254{ 255 // Get a depth texture target from the pooled profile 256 // which is returned as a temporary. 257 GFXTexHandle depthTex( width, height, GFXFormatD24S8, &ShadowMapZProfile, 258 "LightShadowMap::_getDepthTarget()" ); 259 260 return depthTex; 261} 262 263bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc ) 264{ 265 if ( currTexFlag == Material::DynamicLight ) 266 { 267 S32 reg = lsc->mShadowMapSC->getSamplerRegister(); 268 269 if ( reg != -1 ) 270 GFX->setTexture( reg, mShadowMapTex); 271 272 return true; 273 } else if ( currTexFlag == Material::DynamicLightMask ) 274 { 275 S32 reg = lsc->mCookieMapSC->getSamplerRegister(); 276 if ( reg != -1 ) 277 { 278 ShadowMapParams *p = mLight->getExtended<ShadowMapParams>(); 279 280 if ( lsc->mCookieMapSC->getType() == GFXSCT_SamplerCube ) 281 GFX->setCubeTexture( reg, p->getCookieCubeTex() ); 282 else 283 GFX->setTexture( reg, p->getCookieTex() ); 284 } 285 286 return true; 287 } 288 289 return false; 290} 291 292void LightShadowMap::render(RenderPassManager* renderPass, const SceneRenderState *diffuseState) 293{ 294 mDebugTarget.setTexture( NULL ); 295 _render( renderPass, diffuseState ); 296 mDebugTarget.setTexture( mShadowMapTex ); 297 298 // Add it to the used list unless we're been updated. 299 //AssertFatal( !smUsedShadowMaps.contains( this ), "LightShadowMap::render - Used shadow map inserted twice!" ); 300 if(!smUsedShadowMaps.contains(this)) 301 smUsedShadowMaps.push_back( this ); 302} 303 304BaseMatInstance* LightShadowMap::getShadowMaterial( BaseMatInstance *inMat ) const 305{ 306 // See if we have an existing material hook. 307 ShadowMaterialHook *hook = static_cast<ShadowMaterialHook*>( inMat->getHook( ShadowMaterialHook::Type ) ); 308 if ( !hook ) 309 { 310 // Create a hook and initialize it using the incoming material. 311 hook = new ShadowMaterialHook; 312 hook->init( inMat ); 313 inMat->addHook( hook ); 314 } 315 316 return hook->getShadowMat( getShadowType() ); 317} 318 319U32 LightShadowMap::getBestTexSize( U32 scale ) const 320{ 321 const ShadowMapParams *params = mLight->getExtended<ShadowMapParams>(); 322 323 // The view dependent shadows don't scale by screen size. 324 U32 texSize; 325 if ( isViewDependent() ) 326 texSize = params->texSize; 327 else 328 texSize = params->texSize * getMin( 1.0f, mLastScreenSize ); 329 330 // Apply the shadow texture scale and make 331 // sure this is a power of 2. 332 texSize = getNextPow2( texSize * smShadowTexScalar ); 333 334 // Get the max texture size this card supports and 335 // scale it down... ensuring the final texSize can 336 // be scaled up that many times and not go over 337 // the card maximum. 338 U32 maxTexSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 2048 ); 339 if ( scale > 1 ) 340 maxTexSize >>= ( scale - 1 ); 341 342 // Never let the shadow texture get smaller than 16x16 as 343 // it just makes the pool bigger and the fillrate savings 344 // are less and leass as we get smaller. 345 texSize = mClamp( texSize, (U32)16, maxTexSize ); 346 347 // Return it. 348 return texSize; 349} 350 351void LightShadowMap::updatePriority( const SceneRenderState *state, U32 currTimeMs ) 352{ 353 PROFILE_SCOPE( LightShadowMap_updatePriority ); 354 355 mLastCull = currTimeMs; 356 357 if ( isViewDependent() ) 358 { 359 mLastScreenSize = 1.0f; 360 mLastPriority = F32_MAX; 361 return; 362 } 363 364 const Point3F &camPt = state->getCameraPosition(); 365 F32 range = mLight->getRange().x; 366 F32 dist; 367 368 if ( mLight->getType() == LightInfo::Spot ) 369 { 370 // We treat the cone as a cylinder to get the 371 // approximate projection distance. 372 373 Point3F endPt = mLight->getPosition() + ( mLight->getDirection() * range ); 374 Point3F nearPt = MathUtils::mClosestPointOnSegment( mLight->getPosition(), endPt, camPt ); 375 dist = ( camPt - nearPt ).len(); 376 377 F32 radius = range * mSin( mDegToRad( mLight->getOuterConeAngle() * 0.5f ) ); 378 dist -= radius; 379 } 380 else 381 dist = SphereF( mLight->getPosition(), range ).distanceTo( camPt ); 382 383 // Get the approximate screen size of the light. 384 mLastScreenSize = state->projectRadius( dist, range ); 385 mLastScreenSize /= state->getViewport().extent.y; 386 387 // Update the priority. 388 mLastPriority = mPow( mLastScreenSize * 50.0f, 2.0f ); 389 mLastPriority *= mLight->getPriority(); 390} 391 392S32 QSORT_CALLBACK LightShadowMap::cmpPriority( LightShadowMap *const *lsm1, LightShadowMap *const *lsm2 ) 393{ 394 F32 diff = (*lsm1)->getLastPriority() - (*lsm2)->getLastPriority(); 395 return diff > 0.0f ? -1 : ( diff < 0.0f ? 1 : 0 ); 396} 397 398void LightShadowMap::_debugRender( SceneRenderState* shadowRenderState ) 399{ 400 #ifdef TORQUE_DEBUG 401 402 // Skip if light does not have debug rendering enabled. 403 if( !getLightInfo()->isDebugRenderingEnabled() ) 404 return; 405 406 DebugDrawer* drawer = DebugDrawer::get(); 407 if( !drawer ) 408 return; 409 410 if( smDebugRenderFrustums ) 411 shadowRenderState->getCullingState().debugRenderCullingVolumes(); 412 413 #endif 414} 415 416 417LightingShaderConstants::LightingShaderConstants() 418 : mInit( false ), 419 mShader( NULL ), 420 mLightParamsSC(NULL), 421 mLightSpotParamsSC(NULL), 422 mLightPositionSC(NULL), 423 mLightDiffuseSC(NULL), 424 mLightAmbientSC(NULL), 425 mLightConfigDataSC(NULL), 426 mLightSpotDirSC(NULL), 427 mHasVectorLightSC(NULL), 428 mVectorLightDirectionSC(NULL), 429 mVectorLightColorSC(NULL), 430 mVectorLightBrightnessSC(NULL), 431 mShadowMapSC(NULL), 432 mShadowMapSizeSC(NULL), 433 mCookieMapSC(NULL), 434 mRandomDirsConst(NULL), 435 mShadowSoftnessConst(NULL), 436 mAtlasXOffsetSC(NULL), 437 mAtlasYOffsetSC(NULL), 438 mAtlasScaleSC(NULL), 439 mFadeStartLength(NULL), 440 mOverDarkFactorPSSM(NULL), 441 mTapRotationTexSC(NULL), 442 443 mWorldToLightProjSC(NULL), 444 mViewToLightProjSC(NULL), 445 mScaleXSC(NULL), 446 mScaleYSC(NULL), 447 mOffsetXSC(NULL), 448 mOffsetYSC(NULL), 449 mFarPlaneScalePSSM(NULL) 450{ 451} 452 453LightingShaderConstants::~LightingShaderConstants() 454{ 455 if (mShader.isValid()) 456 { 457 mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload ); 458 mShader = NULL; 459 } 460} 461 462void LightingShaderConstants::init(GFXShader* shader) 463{ 464 if (mShader.getPointer() != shader) 465 { 466 if (mShader.isValid()) 467 mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload ); 468 469 mShader = shader; 470 mShader->getReloadSignal().notify( this, &LightingShaderConstants::_onShaderReload ); 471 } 472 473 mLightParamsSC = shader->getShaderConstHandle("$lightParams"); 474 mLightSpotParamsSC = shader->getShaderConstHandle("$lightSpotParams"); 475 476 // NOTE: These are the shader constants used for doing lighting 477 // during the forward pass. Do not confuse these for the deferred 478 // lighting constants which are used from AdvancedLightBinManager. 479 mLightPositionSC = shader->getShaderConstHandle( ShaderGenVars::lightPosition ); 480 mLightDiffuseSC = shader->getShaderConstHandle( ShaderGenVars::lightDiffuse ); 481 mLightAmbientSC = shader->getShaderConstHandle( ShaderGenVars::lightAmbient ); 482 mLightConfigDataSC = shader->getShaderConstHandle( ShaderGenVars::lightConfigData); 483 mLightSpotDirSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotDir ); 484 485 mHasVectorLightSC = shader->getShaderConstHandle(ShaderGenVars::hasVectorLight); 486 mVectorLightDirectionSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightDirection); 487 mVectorLightColorSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightColor); 488 mVectorLightBrightnessSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightBrightness); 489 490 mShadowMapSC = shader->getShaderConstHandle("$shadowMap"); 491 mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize"); 492 493 mCookieMapSC = shader->getShaderConstHandle("$cookieMap"); 494 495 mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness"); 496 mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset"); 497 mAtlasYOffsetSC = shader->getShaderConstHandle("$atlasYOffset"); 498 mAtlasScaleSC = shader->getShaderConstHandle("$atlasScale"); 499 500 mFadeStartLength = shader->getShaderConstHandle("$fadeStartLength"); 501 mOverDarkFactorPSSM = shader->getShaderConstHandle("$overDarkPSSM"); 502 mTapRotationTexSC = shader->getShaderConstHandle( "$gTapRotationTex" ); 503 504 mWorldToLightProjSC = shader->getShaderConstHandle("$worldToLightProj"); 505 mViewToLightProjSC = shader->getShaderConstHandle("$viewToLightProj"); 506 mScaleXSC = shader->getShaderConstHandle("$scaleX"); 507 mScaleYSC = shader->getShaderConstHandle("$scaleY"); 508 mOffsetXSC = shader->getShaderConstHandle("$offsetX"); 509 mOffsetYSC = shader->getShaderConstHandle("$offsetY"); 510 mFarPlaneScalePSSM = shader->getShaderConstHandle("$farPlaneScalePSSM"); 511 512 mInit = true; 513} 514 515void LightingShaderConstants::_onShaderReload() 516{ 517 if (mShader.isValid()) 518 init( mShader ); 519} 520 521MODULE_BEGIN( ShadowMapParams ) 522MODULE_INIT_BEFORE( LightMapParams ) 523MODULE_INIT 524{ 525 ShadowMapParams::Type = "ShadowMapParams" ; 526} 527MODULE_END; 528 529LightInfoExType ShadowMapParams::Type( "" ); 530 531ShadowMapParams::ShadowMapParams( LightInfo *light ) 532 : mShadowMap( NULL ), 533 mLight( light ) 534{ 535 attenuationRatio.set( 0.0f, 1.0f, 1.0f ); 536 shadowType = ShadowType_Spot; 537 overDarkFactor.set(2000.0f, 1000.0f, 500.0f, 100.0f); 538 numSplits = 4; 539 logWeight = 0.91f; 540 texSize = 1024; 541 shadowDistance = 100.0f; 542 shadowSoftness = 0.2f; 543 fadeStartDist = 75.0f; 544 lastSplitTerrainOnly = false; 545 mQuery = GFX->createOcclusionQuery(); 546 547 _validate(); 548} 549 550ShadowMapParams::~ShadowMapParams() 551{ 552 SAFE_DELETE( mQuery ); 553 SAFE_DELETE( mShadowMap ); 554} 555 556void ShadowMapParams::_validate() 557{ 558 switch ( mLight->getType() ) 559 { 560 case LightInfo::Spot: 561 shadowType = ShadowType_Spot; 562 break; 563 564 case LightInfo::Vector: 565 shadowType = ShadowType_PSSM; 566 break; 567 568 case LightInfo::Point: 569 if ( shadowType < ShadowType_Paraboloid ) 570 shadowType = ShadowType_DualParaboloidSinglePass; 571 break; 572 573 default: 574 break; 575 } 576 577 // The texture sizes for shadows should always 578 // be power of 2 in size. 579 texSize = getNextPow2( texSize ); 580 581 // The maximum shadow texture size setting we're 582 // gonna allow... this doesn't use your hardware 583 // settings as you may be on a lower end system 584 // than your target machine. 585 // 586 // We apply the hardware specific limits during 587 // shadow rendering. 588 // 589 U32 maxTexSize = 4096; 590 591 if ( mLight->getType() == LightInfo::Vector ) 592 { 593 numSplits = mClamp( numSplits, 1, 4 ); 594 595 // Adjust the shadow texture size for the PSSM 596 // based on the split count to keep the total 597 // shadow texture size within 4096. 598 if ( numSplits == 2 || numSplits == 4 ) 599 maxTexSize = 4096; 600 if ( numSplits == 3 ) 601 maxTexSize = 2048; 602 } 603 else 604 numSplits = 1; 605 606 // Keep it in a valid range... less than 32 is dumb. 607 texSize = mClamp( texSize, 32, maxTexSize ); 608} 609 610LightShadowMap* ShadowMapParams::getOrCreateShadowMap() 611{ 612 if (mShadowMap) 613 return mShadowMap; 614 615 if ( !mLight->getCastShadows() ) 616 return NULL; 617 618 LightShadowMap* newShadowMap = NULL; 619 620 switch ( mLight->getType() ) 621 { 622 case LightInfo::Spot: 623 newShadowMap = new SingleLightShadowMap( mLight ); 624 break; 625 626 case LightInfo::Vector: 627 newShadowMap = new PSSMLightShadowMap( mLight ); 628 break; 629 630 case LightInfo::Point: 631 632 if ( shadowType == ShadowType_CubeMap ) 633 newShadowMap = new CubeLightShadowMap( mLight ); 634 else if ( shadowType == ShadowType_Paraboloid ) 635 newShadowMap = new ParaboloidLightShadowMap( mLight ); 636 else 637 newShadowMap = new DualParaboloidLightShadowMap( mLight ); 638 break; 639 640 default: 641 break; 642 } 643 644 mShadowMap = newShadowMap; 645 return mShadowMap; 646} 647 648GFXTextureObject* ShadowMapParams::getCookieTex() 649{ 650 if ( cookie.isNotEmpty() && 651 ( mCookieTex.isNull() || 652 cookie != mCookieTex->getPath() ) ) 653 { 654 mCookieTex.set( cookie, 655 &GFXStaticTextureSRGBProfile, 656 "ShadowMapParams::getCookieTex()" ); 657 } 658 else if ( cookie.isEmpty() ) 659 mCookieTex = NULL; 660 661 return mCookieTex.getPointer(); 662} 663 664GFXCubemap* ShadowMapParams::getCookieCubeTex() 665{ 666 if ( cookie.isNotEmpty() && 667 ( mCookieCubeTex.isNull() || 668 cookie != mCookieCubeTex->getPath() ) ) 669 { 670 mCookieCubeTex.set( cookie ); 671 } 672 else if ( cookie.isEmpty() ) 673 mCookieCubeTex = NULL; 674 675 return mCookieCubeTex.getPointer(); 676} 677 678void ShadowMapParams::set( const LightInfoEx *ex ) 679{ 680 // TODO: Do we even need this? 681} 682 683void ShadowMapParams::packUpdate( BitStream *stream ) const 684{ 685 // HACK: We need to work out proper parameter 686 // validation when any field changes on the light. 687 688 ((ShadowMapParams*)this)->_validate(); 689 690 stream->writeInt( shadowType, 8 ); 691 692 mathWrite( *stream, attenuationRatio ); 693 694 stream->write( texSize ); 695 696 stream->write( cookie ); 697 698 stream->write( numSplits ); 699 stream->write( logWeight ); 700 701 mathWrite(*stream, overDarkFactor); 702 703 stream->write( fadeStartDist ); 704 stream->writeFlag( lastSplitTerrainOnly ); 705 706 stream->write( shadowDistance ); 707 708 stream->write( shadowSoftness ); 709} 710 711void ShadowMapParams::unpackUpdate( BitStream *stream ) 712{ 713 ShadowType newType = (ShadowType)stream->readInt( 8 ); 714 if ( shadowType != newType ) 715 { 716 // If the shadow type changes delete the shadow 717 // map so it can be reallocated on the next render. 718 shadowType = newType; 719 SAFE_DELETE( mShadowMap ); 720 } 721 722 mathRead( *stream, &attenuationRatio ); 723 724 stream->read( &texSize ); 725 726 stream->read( &cookie ); 727 728 stream->read( &numSplits ); 729 stream->read( &logWeight ); 730 mathRead(*stream, &overDarkFactor); 731 732 stream->read( &fadeStartDist ); 733 lastSplitTerrainOnly = stream->readFlag(); 734 735 stream->read( &shadowDistance ); 736 737 stream->read( &shadowSoftness ); 738} 739