diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index df7cb37dd..afcd0a662 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -52,6 +52,11 @@ bool AdvancedLightBinManager::smDiffuseLightViz = false; bool AdvancedLightBinManager::smSpecularLightViz = false; bool AdvancedLightBinManager::smDetailLightingViz = false; +S32 AdvancedLightBinManager::smMaximumNumOfLights = -1; +bool AdvancedLightBinManager::smUseLightFade = false; +F32 AdvancedLightBinManager::smLightFadeStart = 50; +F32 AdvancedLightBinManager::smLightFadeEnd = 75; + ImplementEnumType( ShadowFilterMode, "The shadow filtering modes for Advanced Lighting shadows.\n" "@ingroup AdvancedLighting" ) @@ -178,6 +183,15 @@ void AdvancedLightBinManager::consoleInit() Con::addVariable("$AL::DetailLightingViz", TypeBool, &smDetailLightingViz, "Enables debug rendering of the PSSM shadows.\n" "@ingroup AdvancedLighting\n"); + + Con::addVariable("$pref::maximumNumOfLights", + TypeS32, &smMaximumNumOfLights, + "The maximum number of local lights that can be rendered at a time. If set to -1, then no limit.\n"); + + Con::addVariable("$pref::useLightFade", TypeBool, &smUseLightFade, "Indicates if local lights should utilize the distance-based object fadeout logic.\n"); + Con::addVariable("$pref::lightFadeStart", TypeF32, &smLightFadeStart, "Distance at which light fading begins if $pref::useLightFade is on.\n"); + Con::addVariable("$pref::lightFadeEnd", TypeF32, &smLightFadeEnd, "Distance at which light fading should have fully faded if $pref::useLightFade is on.\n"); + } bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize) @@ -260,6 +274,72 @@ void AdvancedLightBinManager::clearAllLights() mNumLightsCulled = 0; } +S32 QSORT_CALLBACK AdvancedLightBinManager::_lightScoreCmp(const LightBinEntry* a, const LightBinEntry* b) +{ + F32 diff = a->lightInfo->getScore() - b->lightInfo->getScore(); + return diff > 0 ? 1 : diff < 0 ? -1 : 0; +} + +void AdvancedLightBinManager::_scoreLights(const MatrixF& cameraTrans) +{ + PROFILE_SCOPE(AdvancedLightBinManager_scoreLights); + + if (!LIGHTMGR) + return; + + // Get all the lights. + const Point3F lumDot(0.2125f, 0.7154f, 0.0721f); + + for (LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++) + { + // Get the light. + LightBinEntry& light = *itr; + + F32 luminace = 0.0f; + F32 weight = 0.0f; + F32 score = 0.0f; + + const bool isSpot = light.lightInfo->getType() == LightInfo::Spot; + const bool isPoint = light.lightInfo->getType() == LightInfo::Point; + + if (isPoint || isSpot) + { + Point3F distVec = light.lightInfo->getPosition() - cameraTrans.getPosition(); + F32 dist = distVec.len(); + + score = dist;// light.lightInfo->getRange().x / mMax(dist, 1.0f); + + // Get the luminocity. + luminace = mDot(light.lightInfo->getColor(), lumDot) * light.lightInfo->getBrightness(); + + weight = light.lightInfo->getPriority(); + + //Distance fading test + if (smUseLightFade) + { + if (dist > smLightFadeStart) + { + F32 brightness = light.lightInfo->getBrightness(); + + float fadeOutAmt = (dist - smLightFadeStart) / (smLightFadeEnd - smLightFadeStart); + fadeOutAmt = 1 - fadeOutAmt; + + light.lightInfo->setFadeAmount(fadeOutAmt); + } + } + else + { + light.lightInfo->setFadeAmount(1.0); + } + } + + light.lightInfo->setScore(score * weight - luminace); + } + + // Sort them! + mLightBin.sort(_lightScoreCmp); +} + void AdvancedLightBinManager::render( SceneRenderState *state ) { PROFILE_SCOPE( AdvancedLightManager_Render ); @@ -354,9 +434,25 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) } } + const Frustum& frustum = state->getCameraFrustum(); + MatrixF invCam(frustum.getTransform()); + invCam.inverse(); + + const MatrixF& cameraTrans = frustum.getTransform(); + + if(smUseLightFade || smMaximumNumOfLights != -1) + _scoreLights(cameraTrans); + + S32 lightCount = 0; + // Blend the lights in the bin to the light buffer for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ ) { + if (smMaximumNumOfLights != -1 && lightCount >= smMaximumNumOfLights) + break; + + lightCount++; + LightBinEntry& curEntry = *itr; LightInfo *curLightInfo = curEntry.lightInfo; if (curEntry.lightInfo->getType() >= LightInfo::Vector) @@ -368,7 +464,7 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) ShadowMapParams *lsp = curLightInfo->getExtended(); // Skip lights which won't affect the scene. - if ( !curLightMat || curLightInfo->getBrightness() <= 0.001f ) + if (!curLightMat || curLightInfo->getBrightness() * curLightInfo->getFadeAmount() <= 0.001f) continue; GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED ); @@ -694,7 +790,7 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light MaterialParameters *matParams = matInstance->getMaterialParameters(); matParams->setSafe( lightColor, lightInfo->getColor() ); - matParams->setSafe( lightBrightness, lightInfo->getBrightness() ); + matParams->setSafe(lightBrightness, lightInfo->getBrightness() * lightInfo->getFadeAmount()); switch( lightInfo->getType() ) { diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index 8b256f533..1ac3a6dd9 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -108,6 +108,11 @@ public: static bool smSpecularLightViz; static bool smDetailLightingViz; + static S32 smMaximumNumOfLights; + static bool smUseLightFade; + static F32 smLightFadeEnd; + static F32 smLightFadeStart; + // Used for console init AdvancedLightBinManager( AdvancedLightManager *lm = NULL, ShadowMapManager *sm = NULL, @@ -130,6 +135,9 @@ public: virtual bool setTargetSize(const Point2I &newTargetSize); + /// Scores the registered lights for sorting/ordering purposes + void _scoreLights(const MatrixF& cameraTrans); + // ConsoleObject interface DECLARE_CONOBJECT(AdvancedLightBinManager); @@ -242,6 +250,8 @@ protected: void _setupPerFrameParameters( const SceneRenderState *state ); void setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light ); + + static S32 QSORT_CALLBACK _lightScoreCmp(const LightBinEntry* a, const LightBinEntry* b); }; #endif // _ADVANCEDLIGHTBINMANAGER_H_ diff --git a/Engine/source/lighting/lightInfo.cpp b/Engine/source/lighting/lightInfo.cpp index ea6455cb6..10e6f0b01 100644 --- a/Engine/source/lighting/lightInfo.cpp +++ b/Engine/source/lighting/lightInfo.cpp @@ -54,6 +54,7 @@ LightInfo::LightInfo() mDynamicRefreshFreq( 8 ), mPriority( 1.0f ), mScore( 0.0f ), + mFadeAmount(1.0f), mDebugRender( false ) { } diff --git a/Engine/source/lighting/lightInfo.h b/Engine/source/lighting/lightInfo.h index 0966b771f..ba45fdc59 100644 --- a/Engine/source/lighting/lightInfo.h +++ b/Engine/source/lighting/lightInfo.h @@ -144,6 +144,9 @@ protected: /// when prioritizing lights for rendering. F32 mScore; + /// A temporary value which holds the amount this light is faded due to distance + F32 mFadeAmount; + /// Whether to render debugging visualizations /// for this light. bool mDebugRender; @@ -206,6 +209,9 @@ public: void setScore( F32 score ) { mScore = score; } F32 getScore() const { return mScore; } + void setFadeAmount(F32 fade) { mFadeAmount = fade; } + F32 getFadeAmount() const { return mFadeAmount; } + bool isDebugRenderingEnabled() const { return mDebugRender; } void enableDebugRendering( bool value ) { mDebugRender = value; }