From 327b8ecdcbb9bf904ac5023f5868f651773dc009 Mon Sep 17 00:00:00 2001 From: "glassmancody.info" Date: Sat, 4 Jun 2022 20:33:21 -0700 Subject: [PATCH 1/2] pass sorted lights to light postprocess light buffers --- components/sceneutil/lightmanager.cpp | 38 +++++++++++++-------------- components/sceneutil/lightmanager.hpp | 8 +++--- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index db5fe6b479..9fcc86a32e 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -1140,32 +1140,30 @@ namespace SceneUtil l.mLightSource = transform.mLightSource; l.mViewBound = viewBound; it->second.push_back(l); - - if (mPPLightBuffer && it->first->getName() == Constants::SceneCamera) - { - const auto* light = l.mLightSource->getLight(frameNum); - if (light->getDiffuse().x() >= 0.f) - { - mPPLightBuffer->setLight(frameNum, light->getPosition(), - light->getDiffuse(), - light->getConstantAttenuation(), - light->getLinearAttenuation(), - light->getQuadraticAttenuation(), - l.mLightSource->getRadius()); - } - } } - } - if (getLightingMethod() == LightingMethod::SingleUBO) - { - if (it->second.size() > static_cast(getMaxLightsInScene() - 1)) + const bool fillPPLights = mPPLightBuffer && it->first->getName() == Constants::SceneCamera; + + if (fillPPLights || getLightingMethod() == LightingMethod::SingleUBO) { auto sorter = [] (const LightSourceViewBound& left, const LightSourceViewBound& right) { return left.mViewBound.center().length2() - left.mViewBound.radius2() < right.mViewBound.center().length2() - right.mViewBound.radius2(); }; - std::sort(it->second.begin() + 1, it->second.end(), sorter); - it->second.erase((it->second.begin() + 1) + (getMaxLightsInScene() - 2), it->second.end()); + + std::sort(it->second.begin(), it->second.end(), sorter); + + if (fillPPLights) + { + for (const auto& bound : it->second) + { + const auto* light = bound.mLightSource->getLight(frameNum); + if (light->getDiffuse().x() >= 0.f) + mPPLightBuffer->setLight(frameNum, light, bound.mLightSource->getRadius()); + } + } + + if (it->second.size() > static_cast(getMaxLightsInScene() - 1)) + it->second.resize(getMaxLightsInScene() - 1); } } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 0457dc323e..915f95c829 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -60,7 +60,7 @@ namespace SceneUtil mIndex[frame % 2] = 0; } - void setLight(size_t frame, const osg::Vec4f& position, osg::Vec4f diffuse, float ac, float al, float aq, float radius) + void setLight(size_t frame, const osg::Light* light, float radius) { size_t frameId = frame % 2; size_t i = mIndex[frameId]; @@ -70,9 +70,9 @@ namespace SceneUtil i *= 3; - mUniformBuffers[frameId]->setElement(i + 0, position); - mUniformBuffers[frameId]->setElement(i + 1, diffuse); - mUniformBuffers[frameId]->setElement(i + 2, osg::Vec4f(ac, al, aq, radius)); + mUniformBuffers[frameId]->setElement(i + 0, light->getPosition()); + mUniformBuffers[frameId]->setElement(i + 1, light->getDiffuse()); + mUniformBuffers[frameId]->setElement(i + 2, osg::Vec4f(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), radius)); mIndex[frameId]++; } From 8146b05c925cf61a344b7c7f22337dfe9165f506 Mon Sep 17 00:00:00 2001 From: "glassmancody.info" Date: Sat, 4 Jun 2022 21:01:01 -0700 Subject: [PATCH 2/2] pass only lights with visible geometry --- components/sceneutil/lightmanager.cpp | 2 ++ components/sceneutil/lightmanager.hpp | 12 +++++++++ components/sceneutil/lightutil.cpp | 35 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 9fcc86a32e..5c81626d9b 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -1156,6 +1156,8 @@ namespace SceneUtil { for (const auto& bound : it->second) { + if (bound.mLightSource->getEmpty()) + continue; const auto* light = bound.mLightSource->getLight(frameNum); if (light->getDiffuse().x() >= 0.f) mPPLightBuffer->setLight(frameNum, light, bound.mLightSource->getRadius()); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 915f95c829..b4d4755056 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -118,6 +118,8 @@ namespace SceneUtil unsigned int mLastAppliedFrame; + bool mEmpty = false; + public: META_Node(SceneUtil, LightSource) @@ -147,6 +149,16 @@ namespace SceneUtil return mActorFade; } + void setEmpty(bool empty) + { + mEmpty = empty; + } + + bool getEmpty() const + { + return mEmpty; + } + /// Get the osg::Light safe for modification in the given frame. /// @par May be used externally to animate the light's color/attenuation properties, /// and is used internally to synchronize the light's position with the position of the LightSource. diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 031899848d..adf36ff04f 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -11,6 +13,33 @@ #include "util.hpp" #include "visitor.hpp" +namespace +{ + class CheckEmptyLightVisitor : public osg::NodeVisitor + { + public: + CheckEmptyLightVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::Drawable& drawable) override + { + if (!mEmpty) + return; + + if (dynamic_cast(&drawable)) + mEmpty = false; + else + traverse(drawable); + } + + void apply(osg::Geometry& geometry) override + { + mEmpty = false; + } + + bool mEmpty = true; + }; +} + namespace SceneUtil { @@ -64,6 +93,12 @@ namespace SceneUtil osg::Group* attachTo = visitor.mFoundNode ? visitor.mFoundNode : node; osg::ref_ptr lightSource = createLightSource(esmLight, lightMask, isExterior, osg::Vec4f(0,0,0,1)); attachTo->addChild(lightSource); + + CheckEmptyLightVisitor emptyVisitor; + node->accept(emptyVisitor); + + lightSource->setEmpty(emptyVisitor.mEmpty); + return lightSource; }