diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 38ead09252..936f266dd1 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1043,24 +1043,6 @@ namespace NifOsg return morphGeom; } - class BoundingBoxCallback : public osg::NodeCallback - { - public: - virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) - { - osg::BoundingBox bb = mDrawable->getBound(); - - static_cast(node)->setMatrix( - osg::Matrix::scale(bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), bb.zMax()-bb.zMin()) * - osg::Matrix::translate(bb.center()) ); - - traverse(node, nv); - } - - osg::Drawable* mDrawable; - }; - - static void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { osg::ref_ptr geode (new osg::Geode); @@ -1091,25 +1073,12 @@ namespace NifOsg influence.mWeights.insert(indexWeight); } influence.mInvBindMatrix = toMatrix(data->bones[i].trafo); + influence.mBoundSphere = osg::BoundingSpheref(data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); map->mMap.insert(std::make_pair(boneName, influence)); } rig->setInfluenceMap(map); - // Compute the bounding box - osg::BoundingBox boundingBox; - - osg::Matrix worldTrans = getWorldTransform(triShape); - for(size_t i = 0;i < bones.length();i++) - { - osg::BoundingSphere boneSphere (data->bones[i].boundSphereCenter, data->bones[i].boundSphereRadius); - osg::Matrix boneWorldTrans(getWorldTransform(bones[i].getPtr())); - osg::Matrix mat = boneWorldTrans * worldTrans.inverse(worldTrans); - SceneUtil::transformBoundingSphere(mat, boneSphere); - boundingBox.expandBy(boneSphere); - } - rig->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(boundingBox)); - geode->addDrawable(rig); // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 9205ef379e..19e5b0ae63 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -6,14 +6,34 @@ #include #include +#include #include "skeleton.hpp" - -#include +#include "util.hpp" namespace SceneUtil { +class UpdateRigBounds : public osg::Drawable::UpdateCallback +{ +public: + UpdateRigBounds() + { + } + + UpdateRigBounds(const UpdateRigBounds& copy, const osg::CopyOp& copyop) + : osg::Drawable::UpdateCallback(copy, copyop) + { + } + + void update(osg::NodeVisitor* nv, osg::Drawable* drw) + { + RigGeometry* rig = static_cast(drw); + + rig->updateBounds(nv); + } +}; + // TODO: make threadsafe for multiple cull threads class UpdateRigGeometry : public osg::Drawable::CullCallback { @@ -40,6 +60,7 @@ public: RigGeometry::RigGeometry() { setCullCallback(new UpdateRigGeometry); + setUpdateCallback(new UpdateRigBounds); setSupportsDisplayList(false); } @@ -125,6 +146,8 @@ bool RigGeometry::initFromParentSkeleton(osg::NodeVisitor* nv) continue; } + mBoneSphereMap[bone] = it->second.mBoundSphere; + const BoneInfluence& bi = it->second; const std::map& weights = it->second.mWeights; @@ -178,19 +201,7 @@ void RigGeometry::update(osg::NodeVisitor* nv) mSkeleton->updateBoneMatrices(nv); - osg::NodePath path; - bool foundSkel = false; - for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) - { - if (!foundSkel) - { - if (*it == mSkeleton) - foundSkel = true; - } - else - path.push_back(*it); - } - osg::Matrixf geomToSkel = osg::computeWorldToLocal(path); + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); // skinning osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); @@ -228,6 +239,47 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); } +void RigGeometry::updateBounds(osg::NodeVisitor *nv) +{ + if (!mSkeleton) + { + if (!initFromParentSkeleton(nv)) + return; + } + + mSkeleton->updateBoneMatrices(nv); + + osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); + osg::BoundingBox box; + for (BoneSphereMap::const_iterator it = mBoneSphereMap.begin(); it != mBoneSphereMap.end(); ++it) + { + Bone* bone = it->first; + osg::BoundingSpheref bs = it->second; + transformBoundingSphere(bone->mMatrixInSkeletonSpace * geomToSkel, bs); + box.expandBy(bs); + } + + setInitialBound(box); +} + +osg::Matrixf RigGeometry::getGeomToSkelMatrix(osg::NodeVisitor *nv) +{ + osg::NodePath path; + bool foundSkel = false; + for (osg::NodePath::const_iterator it = nv->getNodePath().begin(); it != nv->getNodePath().end(); ++it) + { + if (!foundSkel) + { + if (*it == mSkeleton) + foundSkel = true; + } + else + path.push_back(*it); + } + return osg::computeWorldToLocal(path); + +} + void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) { mInfluenceMap = influenceMap; diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index f8458cdfa4..e82f6254a4 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -24,6 +24,7 @@ namespace SceneUtil struct BoneInfluence { osg::Matrixf mInvBindMatrix; + osg::BoundingSpheref mBoundSphere; // std::map mWeights; }; @@ -40,6 +41,8 @@ namespace SceneUtil // Called automatically by our CullCallback void update(osg::NodeVisitor* nv); + // Called automatically by our UpdateCallback + void updateBounds(osg::NodeVisitor* nv); private: osg::ref_ptr mSourceGeometry; @@ -57,7 +60,13 @@ namespace SceneUtil Bone2VertexMap mBone2VertexMap; + typedef std::map BoneSphereMap; + + BoneSphereMap mBoneSphereMap; + bool initFromParentSkeleton(osg::NodeVisitor* nv); + + osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); }; }