Port skeleton based bounding boxes to the new skinning system

Not sure if going to keep this, there's a noticable performance impact.
pull/638/head
scrawl 10 years ago
parent 8971a200f7
commit 63b69db617

@ -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<osg::MatrixTransform*>(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<int, int>& boundTextures, int animflags)
{
osg::ref_ptr<osg::Geode> 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

@ -6,14 +6,34 @@
#include <cstdlib>
#include <osg/MatrixTransform>
#include <osg/io_utils>
#include "skeleton.hpp"
#include <osg/io_utils>
#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<RigGeometry*>(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<unsigned short, float>& 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<osg::Vec3Array*>(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> influenceMap)
{
mInfluenceMap = influenceMap;

@ -24,6 +24,7 @@ namespace SceneUtil
struct BoneInfluence
{
osg::Matrixf mInvBindMatrix;
osg::BoundingSpheref mBoundSphere;
// <vertex index, weight>
std::map<unsigned short, float> 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<osg::Geometry> mSourceGeometry;
@ -57,7 +60,13 @@ namespace SceneUtil
Bone2VertexMap mBone2VertexMap;
typedef std::map<Bone*, osg::BoundingSpheref> BoneSphereMap;
BoneSphereMap mBoneSphereMap;
bool initFromParentSkeleton(osg::NodeVisitor* nv);
osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv);
};
}

Loading…
Cancel
Save