Build and set up a skeleton for meshes

This commit is contained in:
Chris Robinson 2012-07-15 19:07:31 -07:00
parent b1f7fd9f7b
commit ad75b47472

View file

@ -141,9 +141,35 @@ static void fail(const std::string &msg)
abort(); abort();
} }
void buildBones(Ogre::Skeleton *skel, Nif::NiNode *node, Ogre::Bone *parent=NULL)
{
Ogre::Bone *bone = skel->createBone(node->name);
if(parent) parent->addChild(bone);
bone->setOrientation(node->trafo.rotation);
bone->setPosition(node->trafo.pos);
bone->setScale(Ogre::Vector3(node->trafo.scale));
bone->setBindingPose();
bone->setInitialState();
const Nif::NodeList &children = node->children;
for(size_t i = 0;i < children.length();i++)
{
Nif::NiNode *next;
if(!children[i].empty() && (next=dynamic_cast<Nif::NiNode*>(children[i].getPtr())))
buildBones(skel, next, bone);
}
}
void loadResource(Ogre::Resource *resource) void loadResource(Ogre::Resource *resource)
{ {
warn("Found no records in NIF for "+resource->getName()); Ogre::Skeleton *skel = dynamic_cast<Ogre::Skeleton*>(resource);
OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!");
Nif::NIFFile nif(skel->getName());
Nif::NiNode *node = dynamic_cast<Nif::NiNode*>(nif.getRecord(0));
buildBones(skel, node);
} }
static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node, Ogre::SkeletonPtr *skel) static bool createSkeleton(const std::string &name, const std::string &group, Nif::Node *node, Ogre::SkeletonPtr *skel)
@ -499,21 +525,29 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
std::vector<Ogre::Vector3> srcNorms = data->normals; std::vector<Ogre::Vector3> srcNorms = data->normals;
if(skin != NULL) if(skin != NULL)
{ {
#if 0 // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be
// Convert vertices and normals back to bone space // explicitly attached later.
std::vector<Vector3> newVerts(srcVerts.size(), Vector3(0,0,0)); mesh->setSkeletonName(mName);
std::vector<Vector3> newNorms(srcNorms.size(), Vector3(0,0,0));
NiSkinDataRef data = skin->GetSkinData(); // Convert vertices and normals to bone space from bind position. It would be
const std::vector<NiNodeRef> &bones = skin->GetBones(); // better to transform the bones into bind position, but there doesn't seem to
for(size_t b = 0;b < bones.size();b++) // be a reliable way to do that.
std::vector<Ogre::Vector3> newVerts(srcVerts.size(), Ogre::Vector3(0.0f));
std::vector<Ogre::Vector3> newNorms(srcNorms.size(), Ogre::Vector3(1.0f));
const Nif::NiSkinData *data = skin->data.getPtr();
const Nif::NodeList &bones = skin->bones;
for(size_t b = 0;b < bones.length();b++)
{ {
Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform(); Ogre::Matrix4 mat(Ogre::Matrix4::IDENTITY);
mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale),
Ogre::Quaternion(data->bones[b].trafo.rotation));
mat = mat * bones[b]->getWorldTransform();
const std::vector<SkinWeight> &weights = data->GetBoneWeights(b); const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[b].weights;
for(size_t i = 0;i < weights.size();i++) for(size_t i = 0;i < weights.size();i++)
{ {
size_t index = weights[i].index; size_t index = weights[i].vertex;
float weight = weights[i].weight; float weight = weights[i].weight;
newVerts.at(index) += (mat*srcVerts[index]) * weight; newVerts.at(index) += (mat*srcVerts[index]) * weight;
@ -531,7 +565,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
srcVerts = newVerts; srcVerts = newVerts;
srcNorms = newNorms; srcNorms = newNorms;
#endif
} }
else if(!mHasSkel) else if(!mHasSkel)
{ {
@ -653,30 +686,29 @@ class NIFMeshLoader : Ogre::ManualResourceLoader
} }
// Assign bone weights for this TriShape // Assign bone weights for this TriShape
#if 0
if(skin != NULL) if(skin != NULL)
{ {
// Get the skeleton resource, so weights can be applied // Get the skeleton resource, so weights can be applied
Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr();
Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName()); Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName());
skel->touch();
NiSkinDataRef data = skin->GetSkinData(); const Nif::NiSkinData *data = skin->data.getPtr();
const std::vector<NiNodeRef> &bones = skin->GetBones(); const Nif::NodeList &bones = skin->bones;
for(size_t i = 0;i < bones.size();i++) for(size_t i = 0;i < bones.length();i++)
{ {
Ogre::VertexBoneAssignment boneInf; Ogre::VertexBoneAssignment boneInf;
boneInf.boneIndex = skel->getBone(bones[i]->GetName())->getHandle(); boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle();
const std::vector<SkinWeight> &weights = data->GetBoneWeights(i); const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[i].weights;
for(size_t j = 0;j < weights.size();j++) for(size_t j = 0;j < weights.size();j++)
{ {
boneInf.vertexIndex = weights[j].index; boneInf.vertexIndex = weights[j].vertex;
boneInf.weight = weights[j].weight; boneInf.weight = weights[j].weight;
sub->addBoneAssignment(boneInf); sub->addBoneAssignment(boneInf);
} }
} }
} }
#endif
if(mMaterialName.length() > 0) if(mMaterialName.length() > 0)
sub->setMaterialName(mMaterialName); sub->setMaterialName(mMaterialName);