From 304d7e544f80e05f992facf6d78d743649c25ba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 4 Apr 2015 19:19:01 +0200 Subject: [PATCH] Optimize RigGeometry to update skinning in CullCallback --- components/nifosg/nifloader.cpp | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 94885a11b..dd9dbc328 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -362,6 +362,56 @@ namespace } }; + struct FindNearestParentSkeleton : public osg::NodeVisitor + { + osg::ref_ptr _root; + FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} + void apply(osg::Transform& node) + { + if (_root.valid()) + return; + _root = dynamic_cast(&node); + traverse(node); + } + }; + + // RigGeometry is skinned from a CullCallback to prevent unnecessary updates of culled rig geometries. + // Note: this assumes only one cull thread is using the given RigGeometry, there would be a race condition otherwise. + struct UpdateRigGeometry : public osg::Drawable::CullCallback + { + virtual bool cull(osg::NodeVisitor *, osg::Drawable * drw, osg::State *) const + { + osgAnimation::RigGeometry* geom = static_cast(drw); + if (!geom) + return false; + if (!geom->getSkeleton() && !geom->getParents().empty()) + { + FindNearestParentSkeleton finder; + if (geom->getParents().size() > 1) + osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl; + geom->getParents()[0]->accept(finder); + + if (!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )" << std::endl; + return false; + } + geom->buildVertexInfluenceSet(); + geom->setSkeleton(finder._root.get()); + } + + if (!geom->getSkeleton()) + return false; + + if (geom->getNeedToComputeMatrix()) + geom->computeMatrixFromRootSkeleton(); + + geom->update(); + + return false; + } + }; + class RigBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback { public: @@ -1284,6 +1334,10 @@ namespace NifOsg } rig->setInfluenceMap(map); + // Override default update using cull callback instead for efficiency. + rig->setUpdateCallback(NULL); + rig->setCullCallback(new UpdateRigGeometry); + osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix());