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.
c++11
scrawl 10 years ago
parent c92592493e
commit 61aaf0cf70

@ -131,6 +131,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool
std::auto_ptr<ObjectAnimation> 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");

@ -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<osgUtil::CullVisitor*>(nv);
mLightManager->prepareForCamera(cv->getCurrentCamera());
// Possible optimizations:
// - cull list of lights by the camera frustum
// - organize lights in a quad tree
const std::vector<LightManager::LightSourceTransform>& lights = mLightManager->getLights();
if (lights.size())
{
static std::map<osg::Node*, osg::ref_ptr<osg::StateSet> > statesets;
std::map<osg::Node*, osg::ref_ptr<osg::StateSet> >::iterator found = statesets.find(node);
osg::ref_ptr<osg::StateSet> 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<int> lightList;
for (unsigned int i=0; i<lights.size(); ++i)
{
const LightManager::LightSourceTransform& l = lights[i];
if (l.mViewBound.intersects(nodeBound))
lightList.push_back(i);
}
if (lightList.empty())
{
statesets[node] = NULL;
traverse(node, nv);
return;
}
unsigned int maxLights = static_cast<unsigned int> (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<LightSource*>(node), osg::computeLocalToWorld(nv->getNodePath()));
mLightManager->addLight(static_cast<LightSource*>(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 &copy, const osg::CopyOp &copyop)
: 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<osgUtil::CullVisitor*>(nv);
if (!mLightManager)
{
for (unsigned int i=0;i<nv->getNodePath().size(); ++i)
{
if (LightManager* lightManager = dynamic_cast<LightManager*>(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<LightManager::LightSourceTransform>& lights = mLightManager->getLights();
if (lights.size())
{
static std::map<osg::Node*, osg::ref_ptr<osg::StateSet> > statesets;
std::map<osg::Node*, osg::ref_ptr<osg::StateSet> >::iterator found = statesets.find(node);
osg::ref_ptr<osg::StateSet> 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<int> lightList;
for (unsigned int i=0; i<lights.size(); ++i)
{
const LightManager::LightSourceTransform& l = lights[i];
if (l.mViewBound.intersects(nodeBound))
lightList.push_back(i);
}
if (lightList.empty())
{
statesets[node] = NULL;
traverse(node, nv);
return;
}
unsigned int maxLights = static_cast<unsigned int> (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);
}
}

@ -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<size_t, osg::ref_ptr<osg::StateSet> > 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

Loading…
Cancel
Save