advancedLightBinManager.cpp
Engine/source/lighting/advanced/advancedLightBinManager.cpp
Public Variables
Public Functions
ConsoleDocClass(AdvancedLightBinManager , "@brief Rendering Manager responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> lighting, shadows , and global variables affecing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">both.\n\n</a>" "Should not be exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> TorqueScript as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> game object, meant <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only\n\n</a>" " @ingroup Lighting" )
ImplementEnumType(ShadowFilterMode , "The shadow filtering modes <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> Advanced Lighting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shadows.\n</a>" "@ingroup AdvancedLighting" )
Detailed Description
Public Variables
EndImplementEnumType
Public Functions
ConsoleDocClass(AdvancedLightBinManager , "@brief Rendering Manager responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> lighting, shadows , and global variables affecing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">both.\n\n</a>" "Should not be exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> TorqueScript as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> game object, meant <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only\n\n</a>" " @ingroup Lighting" )
IMPLEMENT_CONOBJECT(AdvancedLightBinManager )
ImplementEnumType(ShadowFilterMode , "The shadow filtering modes <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> Advanced Lighting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shadows.\n</a>" "@ingroup AdvancedLighting" )
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/advanced/advancedLightBinManager.h" 26 27#include "lighting/advanced/advancedLightManager.h" 28#include "lighting/advanced/advancedLightBufferConditioner.h" 29#include "lighting/shadowMap/shadowMapManager.h" 30#include "lighting/shadowMap/shadowMapPass.h" 31#include "lighting/shadowMap/lightShadowMap.h" 32#include "lighting/common/lightMapParams.h" 33#include "renderInstance/renderDeferredMgr.h" 34#include "gfx/gfxTransformSaver.h" 35#include "scene/sceneManager.h" 36#include "scene/sceneRenderState.h" 37#include "materials/materialManager.h" 38#include "materials/sceneData.h" 39#include "core/util/safeDelete.h" 40#include "core/util/rgb2luv.h" 41#include "gfx/gfxDebugEvent.h" 42#include "math/util/matrixSet.h" 43#include "console/consoleTypes.h" 44#include "gfx/gfxTextureManager.h" 45 46const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "specularLighting" ); 47const String AdvancedLightBinManager::smBufferName( "specularLighting" ); 48 49ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality; 50bool AdvancedLightBinManager::smPSSMDebugRender = false; 51bool AdvancedLightBinManager::smUseSSAOMask = false; 52bool AdvancedLightBinManager::smDiffuseLightViz = false; 53bool AdvancedLightBinManager::smSpecularLightViz = false; 54bool AdvancedLightBinManager::smDetailLightingViz = false; 55 56S32 AdvancedLightBinManager::smMaximumNumOfLights = -1; 57bool AdvancedLightBinManager::smUseLightFade = false; 58F32 AdvancedLightBinManager::smLightFadeStart = 50; 59F32 AdvancedLightBinManager::smLightFadeEnd = 75; 60 61bool AdvancedLightBinManager::smAllowLocalLightShadows = true; 62 63ImplementEnumType( ShadowFilterMode, 64 "The shadow filtering modes for Advanced Lighting shadows.\n" 65 "@ingroup AdvancedLighting" ) 66 67 { ShadowFilterMode_None, "None", 68 "@brief Simple point sampled filtering.\n" 69 "This is the fastest and lowest quality mode." }, 70 71 { ShadowFilterMode_SoftShadow, "SoftShadow", 72 "@brief A variable tap rotated poisson disk soft shadow filter.\n" 73 "It performs 4 taps to classify the point as in shadow, out of shadow, or along a " 74 "shadow edge. Samples on the edge get an additional 8 taps to soften them." }, 75 76 { ShadowFilterMode_SoftShadowHighQuality, "SoftShadowHighQuality", 77 "@brief A 12 tap rotated poisson disk soft shadow filter.\n" 78 "It performs all the taps for every point without any early rejection." }, 79 80EndImplementEnumType; 81 82// NOTE: The order here matches that of the LightInfo::Type enum. 83const String AdvancedLightBinManager::smLightMatNames[] = 84{ 85 "AL_PointLightMaterial", // LightInfo::Point 86 "AL_SpotLightMaterial", // LightInfo::Spot 87 "AL_VectorLightMaterial", // LightInfo::Vector 88 "", // LightInfo::Ambient 89}; 90 91// NOTE: The order here matches that of the LightInfo::Type enum. 92const GFXVertexFormat* AdvancedLightBinManager::smLightMatVertex[] = 93{ 94 getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Point 95 getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Spot 96 getGFXVertexFormat<FarFrustumQuadVert>(), // LightInfo::Vector 97 NULL, // LightInfo::Ambient 98}; 99 100// NOTE: The order here matches that of the ShadowType enum. 101const String AdvancedLightBinManager::smShadowTypeMacro[] = 102{ 103 "", // ShadowType_Spot 104 "", // ShadowType_PSSM, 105 "", // ShadowType_Paraboloid, 106 "SHADOW_DUALPARABOLOID_SINGLE_PASS", // ShadowType_DualParaboloidSinglePass, 107 "SHADOW_DUALPARABOLOID", // ShadowType_DualParaboloid, 108 "SHADOW_CUBE", // ShadowType_CubeMap, 109}; 110 111AdvancedLightBinManager::RenderSignal &AdvancedLightBinManager::getRenderSignal() 112{ 113 static RenderSignal theSignal; 114 return theSignal; 115} 116 117IMPLEMENT_CONOBJECT(AdvancedLightBinManager); 118 119ConsoleDocClass( AdvancedLightBinManager, 120 "@brief Rendering Manager responsible for lighting, shadows, and global variables affecing both.\n\n" 121 122 "Should not be exposed to TorqueScript as a game object, meant for internal use only\n\n" 123 124 "@ingroup Lighting" 125); 126 127AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = NULL */, 128 ShadowMapManager *sm /* = NULL */, 129 GFXFormat lightBufferFormat /* = GFXFormatR8G8B8A8 */ ) 130 : RenderBinManager( RIT_LightInfo, 1.0f, 1.0f ), 131 mNumLightsCulled(0), 132 mLightManager(lm), 133 mShadowManager(sm) 134{ 135 mMRTLightmapsDuringDeferred = true; 136 137 Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials ); 138 Con::addVariableNotify( "$pref::Shadows::filterMode", callback ); 139 Con::addVariableNotify( "$AL::PSSMDebugRender", callback ); 140 Con::addVariableNotify( "$AL::UseSSAOMask", callback ); 141 Con::addVariableNotify( "$AL::DiffuseLightViz", callback); 142 Con::addVariableNotify( "$AL::SpecularLightViz", callback); 143 Con::addVariableNotify( "$AL::DetailLightingViz", callback); 144} 145 146 147AdvancedLightBinManager::~AdvancedLightBinManager() 148{ 149 _deleteLightMaterials(); 150 151 Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials ); 152 Con::removeVariableNotify( "$pref::shadows::filterMode", callback ); 153 Con::removeVariableNotify( "$AL::PSSMDebugRender", callback ); 154 Con::removeVariableNotify( "$AL::UseSSAOMask", callback ); 155 Con::removeVariableNotify( "$AL::DiffuseLightViz", callback); 156 Con::removeVariableNotify( "$AL::SpecularLightViz", callback); 157 Con::removeVariableNotify( "$AL::DetailLightingViz", callback); 158} 159 160void AdvancedLightBinManager::consoleInit() 161{ 162 Parent::consoleInit(); 163 164 Con::addVariable( "$pref::shadows::filterMode", 165 TYPEID<ShadowFilterMode>(), &smShadowFilterMode, 166 "The filter mode to use for shadows.\n" 167 "@ingroup AdvancedLighting\n" ); 168 169 Con::addVariable( "$AL::UseSSAOMask", TypeBool, &smUseSSAOMask, 170 "Used by the SSAO PostEffect to toggle the sampling of ssaomask " 171 "texture by the light shaders.\n" 172 "@ingroup AdvancedLighting\n" ); 173 174 Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender, 175 "Enables debug rendering of the PSSM shadows.\n" 176 "@ingroup AdvancedLighting\n" ); 177 178 Con::addVariable("$AL::DiffuseLightViz", TypeBool, &smDiffuseLightViz, 179 "Enables debug rendering of the PSSM shadows.\n" 180 "@ingroup AdvancedLighting\n"); 181 182 Con::addVariable("$AL::SpecularLightViz", TypeBool, &smSpecularLightViz, 183 "Enables debug rendering of the PSSM shadows.\n" 184 "@ingroup AdvancedLighting\n"); 185 186 Con::addVariable("$AL::DetailLightingViz", TypeBool, &smDetailLightingViz, 187 "Enables debug rendering of the PSSM shadows.\n" 188 "@ingroup AdvancedLighting\n"); 189 190 Con::addVariable("$pref::maximumNumOfLights", 191 TypeS32, &smMaximumNumOfLights, 192 "The maximum number of local lights that can be rendered at a time. If set to -1, then no limit.\n"); 193 194 Con::addVariable("$pref::useLightFade", TypeBool, &smUseLightFade, "Indicates if local lights should utilize the distance-based object fadeout logic.\n"); 195 Con::addVariable("$pref::lightFadeStart", TypeF32, &smLightFadeStart, "Distance at which light fading begins if $pref::useLightFade is on.\n"); 196 Con::addVariable("$pref::lightFadeEnd", TypeF32, &smLightFadeEnd, "Distance at which light fading should have fully faded if $pref::useLightFade is on.\n"); 197 198 Con::addVariable("$pref::allowLocalLightShadows", TypeBool, &smAllowLocalLightShadows, "Indicates if local lights(point/spot) can cast shadows.\n"); 199 200} 201 202bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize) 203{ 204 /*bool ret = Parent::setTargetSize( newTargetSize ); 205 206 // We require the viewport to match the default. 207 mNamedTarget.setViewport( GFX->getViewport() ); 208 209 return ret;*/ 210 return true; 211} 212 213bool AdvancedLightBinManager::_updateTargets() 214{ 215 /* PROFILE_SCOPE(AdvancedLightBinManager_updateTargets); 216 217 bool ret = Parent::_updateTargets(); 218 219 mDiffuseLightingTarget = NamedTexTarget::find("diffuseLighting"); 220 if (mDiffuseLightingTarget.isValid()) 221 { 222 mDiffuseLightingTex = mDiffuseLightingTarget->getTexture(); 223 224 for (U32 i = 0; i < mTargetChainLength; i++) 225 mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, mDiffuseLightingTex); 226 } 227 228 GFX->finalizeReset(); 229 230 return ret;*/ 231 return true; 232} 233 234void AdvancedLightBinManager::addLight( LightInfo *light ) 235{ 236 // Get the light type. 237 const LightInfo::Type lightType = light->getType(); 238 239 AssertFatal( lightType == LightInfo::Point || 240 lightType == LightInfo::Spot, "Bogus light type." ); 241 242 // Find a shadow map for this light, if it has one 243 ShadowMapParams *lsp = light->getExtended<ShadowMapParams>(); 244 LightShadowMap *lsm = lsp->getShadowMap(); 245 246 // Get the right shadow type. 247 ShadowType shadowType = ShadowType_None; 248 if ( light->getCastShadows() && smAllowLocalLightShadows && 249 lsm && lsm->hasShadowTex() && 250 !ShadowMapPass::smDisableShadows ) 251 shadowType = lsm->getShadowType(); 252 253 // Add the entry 254 LightBinEntry lEntry; 255 lEntry.lightInfo = light; 256 lEntry.shadowMap = lsm; 257 lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() ); 258 259 if( lightType == LightInfo::Spot ) 260 lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer ); 261 else 262 lEntry.vertBuffer = mLightManager->getSphereMesh( lEntry.numPrims, lEntry.primBuffer ); 263 264 // If it's a point light, push front, spot 265 // light, push back. This helps batches. 266 Vector<LightBinEntry> &curBin = mLightBin; 267 if ( light->getType() == LightInfo::Point ) 268 curBin.push_front( lEntry ); 269 else 270 curBin.push_back( lEntry ); 271} 272 273void AdvancedLightBinManager::clearAllLights() 274{ 275 Con::setIntVariable("lightMetrics::activeLights", mLightBin.size()); 276 Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled); 277 278 mLightBin.clear(); 279 mNumLightsCulled = 0; 280} 281 282S32 QSORT_CALLBACK AdvancedLightBinManager::_lightScoreCmp(const LightBinEntry* a, const LightBinEntry* b) 283{ 284 F32 diff = a->lightInfo->getScore() - b->lightInfo->getScore(); 285 return diff > 0 ? 1 : diff < 0 ? -1 : 0; 286} 287 288void AdvancedLightBinManager::_scoreLights(const MatrixF& cameraTrans) 289{ 290 PROFILE_SCOPE(AdvancedLightBinManager_scoreLights); 291 292 if (!LIGHTMGR) 293 return; 294 295 // Get all the lights. 296 const Point3F lumDot(0.2125f, 0.7154f, 0.0721f); 297 298 for (LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++) 299 { 300 // Get the light. 301 LightBinEntry& light = *itr; 302 303 F32 luminace = 0.0f; 304 F32 weight = 0.0f; 305 F32 score = 0.0f; 306 307 const bool isSpot = light.lightInfo->getType() == LightInfo::Spot; 308 const bool isPoint = light.lightInfo->getType() == LightInfo::Point; 309 310 if (isPoint || isSpot) 311 { 312 Point3F distVec = light.lightInfo->getPosition() - cameraTrans.getPosition(); 313 F32 dist = distVec.len(); 314 315 score = dist;// light.lightInfo->getRange().x / mMax(dist, 1.0f); 316 317 // Get the luminocity. 318 luminace = mDot(light.lightInfo->getColor(), lumDot) * light.lightInfo->getBrightness(); 319 320 weight = light.lightInfo->getPriority(); 321 322 //Distance fading test 323 if (smUseLightFade) 324 { 325 if (dist > smLightFadeStart) 326 { 327 F32 brightness = light.lightInfo->getBrightness(); 328 329 float fadeOutAmt = (dist - smLightFadeStart) / (smLightFadeEnd - smLightFadeStart); 330 fadeOutAmt = 1 - fadeOutAmt; 331 332 light.lightInfo->setFadeAmount(fadeOutAmt); 333 } 334 } 335 else 336 { 337 light.lightInfo->setFadeAmount(1.0); 338 } 339 } 340 341 light.lightInfo->setScore(score * weight - luminace); 342 } 343 344 // Sort them! 345 mLightBin.sort(_lightScoreCmp); 346} 347 348void AdvancedLightBinManager::render( SceneRenderState *state ) 349{ 350 PROFILE_SCOPE( AdvancedLightManager_Render ); 351 352 // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass 353 if( state->disableAdvancedLightingBins() ) 354 return; 355 356 // Automagically save & restore our viewport and transforms. 357 GFXTransformSaver saver; 358 359 if( !mLightManager ) 360 return; 361 362 // Get the sunlight. If there's no sun, and no lights in the bins, no draw 363 LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType, false ); 364 GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED ); 365 366 // Tell the superclass we're about to render 367 //if ( !_onPreRender( state ) ) 368 // return; 369 370 NamedTexTargetRef sceneColorTargetRef = NamedTexTarget::find("AL_FormatToken"); 371 if (sceneColorTargetRef.isNull()) 372 return; 373 374 if (mLightingTargetRef.isNull()) 375 mLightingTargetRef = GFX->allocRenderToTextureTarget(); 376 377 //Do a quick pass to update our probes if they're dirty 378 //PROBEMGR->updateDirtyProbes(); 379 380 mLightingTargetRef->attachTexture(GFXTextureTarget::Color0, sceneColorTargetRef->getTexture()); 381 382 GFX->pushActiveRenderTarget(); 383 GFX->setActiveRenderTarget(mLightingTargetRef); 384 385 GFX->setViewport(sceneColorTargetRef->getViewport()); 386 387 // Restore transforms 388 MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); 389 matrixSet.restoreSceneViewProjection(); 390 391 // Set up the SG Data 392 SceneData sgData; 393 sgData.init( state ); 394 395 // There are cases where shadow rendering is disabled. 396 const bool disableShadows = /*state->isReflectPass() || */ShadowMapPass::smDisableShadows; 397 398 // Pick the right material for rendering the sunlight... we only 399 // cast shadows when its enabled and we're not in a reflection. 400 LightMaterialInfo *vectorMatInfo; 401 if ( sunLight && 402 sunLight->getCastShadows() && 403 !disableShadows && 404 sunLight->getExtended<ShadowMapParams>() ) 405 vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false ); 406 else 407 vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false ); 408 409 // Initialize and set the per-frame parameters after getting 410 // the vector light material as we use lazy creation. 411 _setupPerFrameParameters( state ); 412 413 // Draw sunlight/ambient 414 if ( sunLight && vectorMatInfo ) 415 { 416 GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED ); 417 418 // Set up SG data 419 setupSGData( sgData, state, sunLight ); 420 vectorMatInfo->setLightParameters( sunLight, state ); 421 422 // Set light holds the active shadow map. 423 mShadowManager->setLightShadowMapForLight( sunLight ); 424 425 // Set geometry 426 GFX->setVertexBuffer( mFarFrustumQuadVerts ); 427 GFX->setPrimitiveBuffer( NULL ); 428 429 vectorMatInfo->matInstance->mSpecialLight = true; 430 431 // Render the material passes 432 while( vectorMatInfo->matInstance->setupPass( state, sgData ) ) 433 { 434 vectorMatInfo->matInstance->setSceneInfo( state, sgData ); 435 vectorMatInfo->matInstance->setTransforms( matrixSet, state ); 436 GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); 437 } 438 } 439 440 const Frustum& frustum = state->getCameraFrustum(); 441 MatrixF invCam(frustum.getTransform()); 442 invCam.inverse(); 443 444 const MatrixF& cameraTrans = frustum.getTransform(); 445 446 if(smUseLightFade || smMaximumNumOfLights != -1) 447 _scoreLights(cameraTrans); 448 449 S32 lightCount = 0; 450 451 // Blend the lights in the bin to the light buffer 452 for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ ) 453 { 454 if (smMaximumNumOfLights != -1 && lightCount >= smMaximumNumOfLights) 455 break; 456 457 lightCount++; 458 459 LightBinEntry& curEntry = *itr; 460 LightInfo *curLightInfo = curEntry.lightInfo; 461 if (curEntry.lightInfo->getType() >= LightInfo::Vector) 462 continue; 463 LightMaterialInfo *curLightMat = curEntry.lightMaterial; 464 const U32 numPrims = curEntry.numPrims; 465 const U32 numVerts = curEntry.vertBuffer->mNumVerts; 466 467 ShadowMapParams *lsp = curLightInfo->getExtended<ShadowMapParams>(); 468 469 // Skip lights which won't affect the scene. 470 if (!curLightMat || curLightInfo->getBrightness() * curLightInfo->getFadeAmount() <= 0.001f) 471 continue; 472 473 GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED ); 474 475 setupSGData( sgData, state, curLightInfo ); 476 curLightMat->setLightParameters( curLightInfo, state ); 477 mShadowManager->setLightShadowMap( curEntry.shadowMap ); 478 479 // Set geometry 480 GFX->setVertexBuffer( curEntry.vertBuffer ); 481 GFX->setPrimitiveBuffer( curEntry.primBuffer ); 482 483 lsp->getOcclusionQuery()->begin(); 484 485 curLightMat->matInstance->mSpecialLight = false; 486 487 // Render the material passes 488 while( curLightMat->matInstance->setupPass( state, sgData ) ) 489 { 490 // Set transforms 491 matrixSet.setWorld(*sgData.objTrans); 492 curLightMat->matInstance->setTransforms(matrixSet, state); 493 curLightMat->matInstance->setSceneInfo(state, sgData); 494 495 if(curEntry.primBuffer) 496 GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims); 497 else 498 GFX->drawPrimitive(GFXTriangleList, 0, numPrims); 499 } 500 501 lsp->getOcclusionQuery()->end(); 502 } 503 504 // Set NULL for active shadow map (so nothing gets confused) 505 mShadowManager->setLightShadowMap(NULL); 506 GFX->setVertexBuffer( NULL ); 507 GFX->setPrimitiveBuffer( NULL ); 508 509 // Fire off a signal to let others know that light-bin rendering is ending now 510 getRenderSignal().trigger(state, this); 511 512 // Finish up the rendering 513 //_onPostRender(); 514 GFX->popActiveRenderTarget(); 515} 516 517AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial( LightInfo::Type lightType, 518 ShadowType shadowType, 519 bool useCookieTex ) 520{ 521 PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial ); 522 523 // Build the key. 524 const LightMatKey key( lightType, shadowType, useCookieTex ); 525 526 // See if we've already built this one. 527 LightMatTable::Iterator iter = mLightMaterials.find( key ); 528 if ( iter != mLightMaterials.end() ) 529 return iter->value; 530 531 // If we got here we need to build a material for 532 // this light+shadow combination. 533 534 LightMaterialInfo *info = NULL; 535 536 // First get the light material name and make sure 537 // this light has a material in the first place. 538 const String &lightMatName = smLightMatNames[ lightType ]; 539 if ( lightMatName.isNotEmpty() ) 540 { 541 Vector<GFXShaderMacro> shadowMacros; 542 543 // Setup the shadow type macros for this material. 544 if ( shadowType == ShadowType_None ) 545 shadowMacros.push_back( GFXShaderMacro( "NO_SHADOW" ) ); 546 else 547 { 548 shadowMacros.push_back( GFXShaderMacro( smShadowTypeMacro[ shadowType ] ) ); 549 550 // Do we need to do shadow filtering? 551 if ( smShadowFilterMode != ShadowFilterMode_None ) 552 { 553 shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW" ) ); 554 555 const F32 SM = GFX->getPixelShaderVersion(); 556 if ( SM >= 3.0f && smShadowFilterMode == ShadowFilterMode_SoftShadowHighQuality ) 557 shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW_HIGH_QUALITY" ) ); 558 } 559 } 560 561 if ( useCookieTex ) 562 shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) ); 563 564 // Its safe to add the PSSM debug macro to all the materials. 565 if ( smPSSMDebugRender ) 566 shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) ); 567 568 if( smDiffuseLightViz ) 569 shadowMacros.push_back(GFXShaderMacro("DIFFUSE_LIGHT_VIZ")); 570 else if (smSpecularLightViz) 571 shadowMacros.push_back(GFXShaderMacro("SPECULAR_LIGHT_VIZ")); 572 else if (smDetailLightingViz) 573 shadowMacros.push_back(GFXShaderMacro("DETAIL_LIGHTING_VIZ")); 574 575 // Now create the material info object. 576 info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros ); 577 } 578 579 // Push this into the map and return it. 580 mLightMaterials.insertUnique( key, info ); 581 return info; 582} 583 584void AdvancedLightBinManager::_deleteLightMaterials() 585{ 586 LightMatTable::Iterator iter = mLightMaterials.begin(); 587 for ( ; iter != mLightMaterials.end(); iter++ ) 588 delete iter->value; 589 590 mLightMaterials.clear(); 591} 592 593void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state ) 594{ 595 PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters ); 596 const Frustum &frustum = state->getCameraFrustum(); 597 598 MatrixF invCam( frustum.getTransform() ); 599 invCam.inverse(); 600 601 const Point3F *wsFrustumPoints = frustum.getPoints(); 602 const Point3F& cameraPos = frustum.getPosition(); 603 604 // Perform a camera offset. We need to manually perform this offset on the sun (or vector) light's 605 // polygon, which is at the far plane. 606 Point3F cameraOffsetPos = cameraPos; 607 608 // Now build the quad for drawing full-screen vector light 609 // passes.... this is a volatile VB and updates every frame. 610 FarFrustumQuadVert verts[4]; 611 { 612 verts[0].point.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraPos); 613 invCam.mulP(wsFrustumPoints[Frustum::FarTopLeft], &verts[0].normal); 614 verts[0].texCoord.set(-1.0, 1.0); 615 verts[0].tangent.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraOffsetPos); 616 617 verts[1].point.set(wsFrustumPoints[Frustum::FarTopRight] - cameraPos); 618 invCam.mulP(wsFrustumPoints[Frustum::FarTopRight], &verts[1].normal); 619 verts[1].texCoord.set(1.0, 1.0); 620 verts[1].tangent.set(wsFrustumPoints[Frustum::FarTopRight] - cameraOffsetPos); 621 622 verts[2].point.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos); 623 invCam.mulP(wsFrustumPoints[Frustum::FarBottomLeft], &verts[2].normal); 624 verts[2].texCoord.set(-1.0, -1.0); 625 verts[2].tangent.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos); 626 627 verts[3].point.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraPos); 628 invCam.mulP(wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal); 629 verts[3].texCoord.set(1.0, -1.0); 630 verts[3].tangent.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraOffsetPos); 631 } 632 mFarFrustumQuadVerts.set( GFX, 4 ); 633 dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) ); 634 mFarFrustumQuadVerts.unlock(); 635 636 PlaneF farPlane(wsFrustumPoints[Frustum::FarBottomLeft], wsFrustumPoints[Frustum::FarTopLeft], wsFrustumPoints[Frustum::FarTopRight]); 637 PlaneF vsFarPlane(verts[0].normal, verts[1].normal, verts[2].normal); 638 639 // Parameters calculated, assign them to the materials 640 LightMatTable::Iterator iter = mLightMaterials.begin(); 641 for ( ; iter != mLightMaterials.end(); iter++ ) 642 { 643 if ( iter->value ) 644 iter->value->setViewParameters( frustum.getNearDist(), 645 frustum.getFarDist(), 646 frustum.getPosition(), 647 farPlane, 648 vsFarPlane); 649 } 650} 651 652void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light ) 653{ 654 PROFILE_SCOPE( AdvancedLightBinManager_setupSGData ); 655 656 data.lights[0] = light; 657 data.ambientLightColor = state->getAmbientLightColor(); 658 data.objTrans = &MatrixF::Identity; 659 660 if ( light ) 661 { 662 if ( light->getType() == LightInfo::Point ) 663 { 664 // The point light volume gets some flat spots along 665 // the perimiter mostly visible in the constant and 666 // quadradic falloff modes. 667 // 668 // To account for them slightly increase the scale 669 // instead of greatly increasing the polycount. 670 671 mLightMat = light->getTransform(); 672 mLightMat.scale( light->getRange() * 1.01f ); 673 data.objTrans = &mLightMat; 674 } 675 else if ( light->getType() == LightInfo::Spot ) 676 { 677 mLightMat = light->getTransform(); 678 679 // Rotate it to face down the -y axis. 680 MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) ); 681 682 // Calculate the radius based on the range and angle. 683 F32 range = light->getRange().x; 684 F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f ); 685 686 // NOTE: This fudge makes the cone a little bigger 687 // to remove the facet egde of the cone geometry. 688 radius *= 1.1f; 689 690 // Use the scale to distort the cone to 691 // match our radius and range. 692 scaleRotateTranslate.scale( Point3F( radius, radius, range ) ); 693 694 // Apply the transform and set the position. 695 mLightMat *= scaleRotateTranslate; 696 mLightMat.setPosition( light->getPosition() ); 697 698 data.objTrans = &mLightMat; 699 } 700 } 701} 702 703void AdvancedLightBinManager::MRTLightmapsDuringDeferred( bool val ) 704{ 705 // Do not enable if the GFX device can't do MRT's 706 if ( GFX->getNumRenderTargets() < 2 ) 707 val = false; 708 709 if ( mMRTLightmapsDuringDeferred != val ) 710 { 711 mMRTLightmapsDuringDeferred = val; 712 713 // Reload materials to cause a feature recalculation on deferred materials 714 if(mLightManager->isActive()) 715 MATMGR->flushAndReInitInstances(); 716 717 RenderDeferredMgr *deferred; 718 if ( Sim::findObject( "AL_DeferredBin", deferred ) && deferred->getTargetTexture( 0 ) ) 719 deferred->updateTargets(); 720 } 721} 722 723AdvancedLightBinManager::LightMaterialInfo::LightMaterialInfo( const String &matName, 724 const GFXVertexFormat *vertexFormat, 725 const Vector<GFXShaderMacro> ¯os ) 726: matInstance(NULL), 727 zNearFarInvNearFar(NULL), 728 farPlane(NULL), 729 vsFarPlane(NULL), 730 negFarPlaneDotEye(NULL), 731 lightPosition(NULL), 732 lightDirection(NULL), 733 lightColor(NULL), 734 lightRange(NULL), 735 lightInvSqrRange(NULL), 736 lightAmbient(NULL), 737 lightSpotParams(NULL) 738{ 739 Material *mat = MATMGR->getMaterialDefinitionByName( matName ); 740 if ( !mat ) 741 return; 742 743 matInstance = new LightMatInstance( *mat ); 744 745 for ( U32 i=0; i < macros.size(); i++ ) 746 matInstance->addShaderMacro( macros[i].name, macros[i].value ); 747 748 matInstance->init( MATMGR->getDefaultFeatures(), vertexFormat ); 749 750 lightDirection = matInstance->getMaterialParameterHandle("$lightDirection"); 751 lightAmbient = matInstance->getMaterialParameterHandle("$lightAmbient"); 752 lightSpotParams = matInstance->getMaterialParameterHandle("$lightSpotParams"); 753 lightRange = matInstance->getMaterialParameterHandle("$lightRange"); 754 lightInvSqrRange = matInstance->getMaterialParameterHandle("$lightInvSqrRange"); 755 lightPosition = matInstance->getMaterialParameterHandle("$lightPosition"); 756 farPlane = matInstance->getMaterialParameterHandle("$farPlane"); 757 vsFarPlane = matInstance->getMaterialParameterHandle("$vsFarPlane"); 758 negFarPlaneDotEye = matInstance->getMaterialParameterHandle("$negFarPlaneDotEye"); 759 zNearFarInvNearFar = matInstance->getMaterialParameterHandle("$zNearFarInvNearFar"); 760 lightColor = matInstance->getMaterialParameterHandle("$lightColor"); 761 lightBrightness = matInstance->getMaterialParameterHandle("$lightBrightness"); 762} 763 764AdvancedLightBinManager::LightMaterialInfo::~LightMaterialInfo() 765{ 766 SAFE_DELETE(matInstance); 767} 768 769void AdvancedLightBinManager::LightMaterialInfo::setViewParameters( const F32 _zNear, 770 const F32 _zFar, 771 const Point3F &_eyePos, 772 const PlaneF &_farPlane, 773 const PlaneF &_vsFarPlane) 774{ 775 MaterialParameters *matParams = matInstance->getMaterialParameters(); 776 777 matParams->setSafe( farPlane, *((const Point4F *)&_farPlane) ); 778 779 matParams->setSafe( vsFarPlane, *((const Point4F *)&_vsFarPlane) ); 780 781 if ( negFarPlaneDotEye->isValid() ) 782 { 783 // -dot( farPlane, eyePos ) 784 const F32 negFarPlaneDotEyeVal = -( mDot( *((const Point3F *)&_farPlane), _eyePos ) + _farPlane.d ); 785 matParams->set( negFarPlaneDotEye, negFarPlaneDotEyeVal ); 786 } 787 788 matParams->setSafe( zNearFarInvNearFar, Point4F( _zNear, _zFar, 1.0f / _zNear, 1.0f / _zFar ) ); 789} 790 791void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState ) 792{ 793 MaterialParameters *matParams = matInstance->getMaterialParameters(); 794 795 matParams->setSafe( lightColor, lightInfo->getColor() ); 796 matParams->setSafe(lightBrightness, lightInfo->getBrightness() * lightInfo->getFadeAmount()); 797 798 switch( lightInfo->getType() ) 799 { 800 case LightInfo::Vector: 801 { 802 matParams->setSafe( lightDirection, lightInfo->getDirection()); 803 matParams->setSafe( lightAmbient, renderState->getAmbientLightColor()); 804 } 805 break; 806 807 case LightInfo::Spot: 808 { 809 const F32 outerCone = lightInfo->getOuterConeAngle(); 810 const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone); 811 const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f)); 812 const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f)); 813 Point2F spotParams(outerCos,innerCos - outerCos); 814 815 matParams->setSafe( lightSpotParams, spotParams ); 816 matParams->setSafe( lightDirection, lightInfo->getDirection()); 817 matParams->setSafe( lightPosition, lightInfo->getPosition()); 818 819 const F32 radius = lightInfo->getRange().x; 820 const F32 invSqrRadius = 1.0f / mSquared(radius); 821 matParams->setSafe(lightRange, radius); 822 matParams->setSafe(lightInvSqrRange, invSqrRadius); 823 } 824 break; 825 826 case LightInfo::Point: 827 { 828 matParams->setSafe(lightPosition, lightInfo->getPosition()); 829 830 const F32 radius = lightInfo->getRange().x; 831 const F32 invSqrRadius = 1.0f / (radius * radius); 832 matParams->setSafe( lightRange, radius); 833 matParams->setSafe( lightInvSqrRange, invSqrRadius); 834 } 835 break; 836 837 default: 838 AssertFatal( false, "Bad light type!" ); 839 break; 840 } 841} 842 843bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData ) 844{ 845 // Go no further if the material failed to initialize properly. 846 if ( !mProcessedMaterial || 847 mProcessedMaterial->getNumPasses() == 0 ) 848 return false; 849 850 U32 reflectStatus = Base; 851 if (state->isReflectPass()) 852 reflectStatus = Reflecting; 853 854 // Fetch the lightmap params 855 const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>(); 856 857 // If no Lightmap params, let parent handle it 858 if(lmParams == NULL) 859 return Parent::setupPass(state, sgData); 860 861 // Defaults 862 bool bRetVal = true; 863 864 // What render pass is this... 865 if(mCurPass == -1) 866 { 867 // First pass, reset this flag 868 mInternalPass = false; 869 870 // Pass call to parent 871 bRetVal = Parent::setupPass(state, sgData); 872 } 873 else 874 { 875 // If this light is represented in a lightmap, it has already done it's 876 // job for non-lightmapped geometry. Now render the lightmapped geometry 877 // pass (specular + shadow-darkening) 878 if(!mInternalPass && lmParams->representedInLightmap) 879 mInternalPass = true; 880 else 881 return Parent::setupPass(state, sgData); 882 } 883 884 // Set up the shader constants we need to... 885 if(mLightMapParamsSC->isValid()) 886 { 887 // If this is an internal pass, special case the parameters 888 if(mInternalPass) 889 { 890 AssertFatal( lmParams->shadowDarkenColor.alpha == -1.0f, "Assumption failed, check unpack code!" ); 891 getMaterialParameters()->set( mLightMapParamsSC, lmParams->shadowDarkenColor ); 892 } 893 else 894 getMaterialParameters()->set( mLightMapParamsSC, LinearColorF::WHITE ); 895 } 896 897 // Now override stateblock with our own 898 if(!mInternalPass) 899 { 900 // If this is not an internal pass, and this light is represented in lightmaps 901 // than only effect non-lightmapped geometry for this pass 902 if (lmParams->representedInLightmap) 903 { 904 GFX->setStateBlock(mLitState[StaticLightNonLMGeometry][reflectStatus]); 905 } 906 else // This is a normal, dynamic light. 907 { 908 if (mSpecialLight) 909 GFX->setStateBlock(mLitState[SunLight][reflectStatus]); 910 else 911 GFX->setStateBlock(mLitState[DynamicLight][reflectStatus]); 912 } 913 914 } 915 else // Internal pass, this is the add-specular/multiply-darken-color pass 916 GFX->setStateBlock(mLitState[StaticLightLMGeometry][reflectStatus]); 917 918 return bRetVal; 919} 920 921bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat ) 922{ 923 bool success = Parent::init(features, vertexFormat); 924 925 // If the initialization failed don't continue. 926 if ( !success || !mProcessedMaterial || mProcessedMaterial->getNumPasses() == 0 ) 927 return false; 928 929 mLightMapParamsSC = getMaterialParameterHandle("$lightMapParams"); 930 931 // Grab the state block for the first render pass (since this mat instance 932 // inserts a pass after the first pass) 933 AssertFatal(mProcessedMaterial->getNumPasses() > 0, "No passes created! Ohnoes"); 934 const RenderPassData *rpd = mProcessedMaterial->getPass(0); 935 AssertFatal(rpd, "No render pass data!"); 936 AssertFatal(rpd->mRenderStates[0], "No render state 0!"); 937 938 // Get state block desc for normal (not wireframe, not translucent, not glow, etc) 939 // render state 940 GFXStateBlockDesc litState = rpd->mRenderStates[0]->getDesc(); 941 942 // Create state blocks for each of the 3 possible combos in setupPass 943 944 //DynamicLight State: This will effect lightmapped and non-lightmapped geometry 945 // in the same way. 946 947 litState.separateAlphaBlendDefined = true; 948 litState.separateAlphaBlendEnable = false; 949 litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask; 950 litState.setCullMode(GFXCullCW); 951 mLitState[DynamicLight][Base] = GFX->createStateBlock(litState); 952 litState.setCullMode(GFXCullCCW); 953 mLitState[DynamicLight][Reflecting] = GFX->createStateBlock(litState); 954 955 litState.separateAlphaBlendDefined = true; 956 litState.separateAlphaBlendEnable = false; 957 litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask; 958 litState.setCullMode(GFXCullCCW); 959 mLitState[SunLight][Base] = GFX->createStateBlock(litState); 960 litState.setCullMode(GFXCullCCW); 961 mLitState[SunLight][Reflecting] = GFX->createStateBlock(litState); 962 963 // StaticLightNonLMGeometry State: This will treat non-lightmapped geometry 964 // in the usual way, but will not effect lightmapped geometry. 965 litState.separateAlphaBlendDefined = true; 966 litState.separateAlphaBlendEnable = false; 967 litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask; 968 litState.setCullMode(GFXCullCW); 969 mLitState[StaticLightNonLMGeometry][Base] = GFX->createStateBlock(litState); 970 litState.setCullMode(GFXCullCCW); 971 mLitState[StaticLightNonLMGeometry][Reflecting] = GFX->createStateBlock(litState); 972 973 // StaticLightLMGeometry State: This will add specular information (alpha) but 974 // multiply-darken color information. 975 litState.blendDest = GFXBlendSrcColor; 976 litState.blendSrc = GFXBlendZero; 977 litState.stencilMask = RenderDeferredMgr::OpaqueStaticLitMask; 978 litState.separateAlphaBlendDefined = true; 979 litState.separateAlphaBlendEnable = true; 980 litState.separateAlphaBlendSrc = GFXBlendOne; 981 litState.separateAlphaBlendDest = GFXBlendOne; 982 litState.separateAlphaBlendOp = GFXBlendOpAdd; 983 litState.setCullMode(GFXCullCW); 984 mLitState[StaticLightLMGeometry][Base] = GFX->createStateBlock(litState); 985 litState.setCullMode(GFXCullCCW); 986 mLitState[StaticLightLMGeometry][Reflecting] = GFX->createStateBlock(litState); 987 988 return true; 989} 990