mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
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.
This commit is contained in:
parent
c92592493e
commit
61aaf0cf70
3 changed files with 109 additions and 135 deletions
|
@ -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 ©, 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<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…
Reference in a new issue