Place Drawables directly in the scene graph when built with OSG 3.4

OSG 3.4 adds the ability to place Drawables directly in the scene graph, without a Geode decorating them. Leveraging this should give a small performance boost, because the redundant Geodes increase culling overhead.

There is still an oustanding issue with the RemoveDrawableVisitor no longer working correctly, because Drawables can have multiple parents.
openmw-37
scrawl 9 years ago
parent 35459f20d5
commit f1ac408f35

@ -11,6 +11,7 @@
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Material>
#include <osg/Version>
#include <osgParticle/ParticleSystem>
@ -196,10 +197,18 @@ namespace
traverse(node);
}
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{
mToRemove.push_back(&drw);
}
#endif
void remove()
{
for (std::vector<osg::Node*>::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{
// FIXME: a Drawable might have more than one parent
osg::Node* node = *it;
if (node->getNumParents())
node->getParent(0)->removeChild(node);
@ -219,6 +228,18 @@ namespace
}
virtual void apply(osg::Geode &node)
{
applyImpl(node);
}
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{
applyImpl(drw);
}
#endif
void applyImpl(osg::Node& node)
{
const std::string toFind = "tri bip";
if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0)
@ -232,6 +253,7 @@ namespace
{
for (std::vector<osg::Node*>::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{
// FIXME: a Drawable might have more than one parent
osg::Node* node = *it;
if (node->getNumParents())
node->getParent(0)->removeChild(node);

@ -6,6 +6,7 @@
#include <osg/Geode>
#include <osg/PositionAttitudeTransform>
#include <osg/UserDataContainer>
#include <osg/Version>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor>
@ -54,11 +55,19 @@ namespace
for (std::vector<osgParticle::ParticleSystem*>::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it)
geode.removeDrawable(*it);
}
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
mToRemove.push_back(partsys);
}
#endif
void remove()
{
for (std::vector<osg::ref_ptr<osg::Node> >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{
// FIXME: a Drawable might have more than one parent
osg::Node* node = *it;
if (node->getNumParents())
node->getParent(0)->removeChild(node);

@ -351,33 +351,36 @@ public:
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drw = geode.getDrawable(i);
apply(*drw);
}
}
void apply(osg::Drawable& drw)
{
osg::Geometry* geom = drw.asGeometry();
if (!geom)
return;
osg::Geometry* geom = drw->asGeometry();
if (!geom)
continue;
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements());
for (unsigned int i=0; i<colors->size(); ++i)
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements());
for (unsigned int i=0; i<colors->size(); ++i)
{
float alpha = 1.f;
if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row
else if (mMeshType == 1)
{
float alpha = 1.f;
if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row
else if (mMeshType == 1)
{
if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row
else if (i>= 33 && i <= 48) alpha = 0.25098; // second row
else alpha = 1.f;
}
else if (mMeshType == 2)
{
osg::Vec4Array* origColors = static_cast<osg::Vec4Array*>(geom->getColorArray());
alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f;
}
(*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha);
if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row
else if (i>= 33 && i <= 48) alpha = 0.25098; // second row
else alpha = 1.f;
}
else if (mMeshType == 2)
{
osg::Vec4Array* origColors = static_cast<osg::Vec4Array*>(geom->getColorArray());
alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f;
}
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
(*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha);
}
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
}
private:

@ -5,6 +5,7 @@
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Array>
#include <osg/Version>
// resource
#include <components/misc/stringops.hpp>
@ -885,9 +886,6 @@ namespace NifOsg
// localToWorldMatrix for transforming to particle space
handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
std::vector<const Nif::Property*> drawableProps;
collectDrawableProperties(nifNode, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, true, animflags);
@ -907,13 +905,21 @@ namespace NifOsg
updater->addParticleSystem(partsys);
parentNode->addChild(updater);
#if not(OSG_MIN_VERSION_REQUIRED(3,3,3))
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
osg::Node* toAttach = geode.get();
#else
osg::Node* toAttach = partsys.get();
#endif
if (rf == osgParticle::ParticleProcessor::RELATIVE_RF)
parentNode->addChild(geode);
parentNode->addChild(toAttach);
else
{
osg::MatrixTransform* trans = new osg::MatrixTransform;
trans->setUpdateCallback(new InverseWorldMatrix);
trans->addChild(geode);
trans->addChild(toAttach);
parentNode->addChild(trans);
}
}
@ -957,8 +963,6 @@ namespace NifOsg
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
osg::ref_ptr<osg::Geometry> geometry;
for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next)
{
@ -981,21 +985,36 @@ namespace NifOsg
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
#if not(OSG_MIN_VERSION_REQUIRED(3,3,3))
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(geometry);
#endif
if (geometry->getDataVariance() == osg::Object::DYNAMIC)
{
// Add a copy, we will alternate between the two copies every other frame using the FrameSwitch
// This is so we can set the DataVariance as STATIC, giving a huge performance boost
geometry->setDataVariance(osg::Object::STATIC);
osg::ref_ptr<osg::Geode> geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
#if not(OSG_MIN_VERSION_REQUIRED(3,3,3))
osg::ref_ptr<osg::Geode> geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(geode);
frameswitch->addChild(geode2);
#else
osg::ref_ptr<osg::Geometry> geom2 = static_cast<osg::Geometry*>(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(geometry);
frameswitch->addChild(geom2);
#endif
parentNode->addChild(frameswitch);
}
else
#if not(OSG_MIN_VERSION_REQUIRED(3,3,3))
parentNode->addChild(geode);
#else
parentNode->addChild(geometry);
#endif
}
osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
@ -1056,8 +1075,6 @@ namespace NifOsg
void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
const std::vector<int>& boundTextures, int animflags)
{
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
@ -1090,17 +1107,27 @@ namespace NifOsg
}
rig->setInfluenceMap(map);
geode->addDrawable(rig);
// Add a copy, we will alternate between the two copies every other frame using the FrameSwitch
// This is so we can set the DataVariance as STATIC, giving a huge performance boost
rig->setDataVariance(osg::Object::STATIC);
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
#if not(OSG_MIN_VERSION_REQUIRED(3,3,3))
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(rig);
osg::Geode* geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|
osg::CopyOp::DEEP_COPY_DRAWABLES));
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
frameswitch->addChild(geode);
frameswitch->addChild(geode2);
#else
SceneUtil::RigGeometry* rig2 = static_cast<SceneUtil::RigGeometry*>(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES|
osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(rig);
frameswitch->addChild(rig2);
#endif
parentNode->addChild(frameswitch);
}

@ -3,6 +3,7 @@
#include <osg/Node>
#include <osg/Geode>
#include <osg/UserDataContainer>
#include <osg/Version>
#include <osgParticle/ParticleSystem>
@ -32,30 +33,47 @@ namespace
{
}
void apply(osg::Node& node)
bool isWorldSpaceParticleSystem(osgParticle::ParticleSystem* partsys)
{
if (osg::Geode* geode = node.asGeode())
// HACK: ParticleSystem has no getReferenceFrame()
return (partsys->getUserDataContainer()
&& partsys->getUserDataContainer()->getNumDescriptions() > 0
&& partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace");
}
void apply(osg::Geode& geode)
{
for (unsigned int i=0;i<geode.getNumDrawables();++i)
{
for (unsigned int i=0;i<geode->getNumDrawables();++i)
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(geode.getDrawable(i)))
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(geode->getDrawable(i)))
if (isWorldSpaceParticleSystem(partsys))
{
// HACK: ParticleSystem has no getReferenceFrame()
if (partsys->getUserDataContainer()
&& partsys->getUserDataContainer()->getNumDescriptions() > 0
&& partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace")
{
// HACK: Ignore the InverseWorldMatrix transform the geode is attached to
if (geode->getNumParents() && geode->getParent(0)->getNumParents())
transformInitialParticles(partsys, geode->getParent(0)->getParent(0));
}
geode->setNodeMask(mMask);
// HACK: Ignore the InverseWorldMatrix transform the geode is attached to
if (geode.getNumParents() && geode.getParent(0)->getNumParents())
transformInitialParticles(partsys, geode.getParent(0)->getParent(0));
}
geode.setNodeMask(mMask);
}
}
}
traverse(node);
#if OSG_MIN_VERSION_REQUIRED(3,3,3)
// in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them.
void apply(osg::Drawable& drw)
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
{
if (isWorldSpaceParticleSystem(partsys))
{
// HACK: Ignore the InverseWorldMatrix transform the particle system is attached to
if (partsys->getNumParents() && partsys->getParent(0)->getNumParents())
transformInitialParticles(partsys, partsys->getParent(0)->getParent(0));
}
partsys->setNodeMask(mMask);
}
}
#endif
void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node)
{

@ -22,11 +22,13 @@ namespace SceneUtil
void DisableFreezeOnCullVisitor::apply(osg::Geode &geode)
{
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drw = geode.getDrawable(i);
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(drw))
partsys->setFreezeOnCull(false);
}
apply(*geode.getDrawable(i));
}
void DisableFreezeOnCullVisitor::apply(osg::Drawable& drw)
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
partsys->setFreezeOnCull(false);
}
}

@ -35,6 +35,7 @@ namespace SceneUtil
}
virtual void apply(osg::Geode &geode);
virtual void apply(osg::Drawable& drw);
};
}

Loading…
Cancel
Save