From 61aaf0cf70f12411d3da47ad65155d5314079528 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 12 Apr 2015 18:02:29 +0200 Subject: [PATCH] Attach light lists to the object base nodes instead of each renderable Apparently that is how Ogre worked (on the SceneNode) so let's roll with it for now. Have not tested yet what MW does. --- apps/openmw/mwrender/objects.cpp | 3 + components/sceneutil/lightmanager.cpp | 218 ++++++++++---------------- components/sceneutil/lightmanager.hpp | 23 ++- 3 files changed, 109 insertions(+), 135 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6d37fa1e8..764aa13c6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -131,6 +131,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { SceneUtil::FindByNameVisitor visitor("AttachLight"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 60315ba7d..5bccd53b3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -45,122 +45,6 @@ namespace SceneUtil } }; - class CullCallback : public osg::NodeCallback - { - public: - CullCallback() - : mLightManager(NULL) - {} - CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) - {} - CullCallback(LightManager* lightManager) - : mLightManager(lightManager) - {} - - META_Object(NifOsg, CullCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = static_cast(nv); - - mLightManager->prepareForCamera(cv->getCurrentCamera()); - - // Possible optimizations: - // - cull list of lights by the camera frustum - // - organize lights in a quad tree - - const std::vector& lights = mLightManager->getLights(); - - if (lights.size()) - { - - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) - { - stateset = found->second; - } - else{ - - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; - - // TODO: sort lights by certain criteria - - while (lightList.size() > maxLights) - lightList.pop_back(); - } - - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; - } - - if (stateset) - cv->pushStateSet(stateset); - - traverse(node, nv); - - if (stateset) - cv->popStateSet(); - } - else - traverse(node, nv); - } - - private: - LightManager* mLightManager; - }; - - class AttachCullCallbackVisitor : public osg::NodeVisitor - { - public: - AttachCullCallbackVisitor(LightManager* lightManager) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mLightManager(lightManager) - { - } - - virtual void apply(osg::Geode &geode) - { - if (!geode.getNumParents()) - return; - - // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call - // does not traverse the drawables, so the push/pop in the CullCallback has no effect - // Should be no longer an issue with osg trunk - osg::Node* parent = geode.getParent(0); - parent->addCullCallback(new CullCallback(mLightManager)); - } - - private: - LightManager* mLightManager; - }; - // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -191,7 +75,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -224,7 +108,6 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) - , mDecorated(false) , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); @@ -233,29 +116,16 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mLightsInViewSpace(false) - , mDecorated(copy.mDecorated) , mStartLight(copy.mStartLight) { } - void LightManager::decorateGeodes() - { - AttachCullCallbackVisitor visitor(this); - accept(visitor); - } - void LightManager::update() { mLightsInViewSpace = false; mLights.clear(); mStateSetCache.clear(); - - if (!mDecorated) - { - decorateGeodes(); - mDecorated = true; - } } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -338,4 +208,90 @@ namespace SceneUtil setUpdateCallback(new CollectLightCallback); } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + return; + } + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > maxLights) + lightList.pop_back(); + } + + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + + if (stateset) + cv->pushStateSet(stateset); + + traverse(node, nv); + + if (stateset) + cv->popStateSet(); + } + else + traverse(node, nv); + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index fe5dc5082..1cd73589a 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -71,8 +71,6 @@ namespace SceneUtil void prepareForCamera(osg::Camera* cam); - void decorateGeodes(); - struct LightSourceTransform { LightSource* mLightSource; @@ -102,11 +100,28 @@ namespace SceneUtil typedef std::map > LightStateSetMap; LightStateSetMap mStateSetCache; - bool mDecorated; - int mStartLight; }; + class LightListCallback : public osg::NodeCallback + { + public: + LightListCallback() + : mLightManager(NULL) + {} + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + + META_Object(NifOsg, LightListCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightManager* mLightManager; + }; + + } #endif