Browse Source

Assimp: Support skeletons with unconnected bones

We needed to detect islands of bones and create anims and parts for them.
Mitchell Stokes 10 years ago
parent
commit
1df9be6fc0
1 changed files with 46 additions and 22 deletions
  1. 46 22
      pandatool/src/assimp/assimpLoader.cxx

+ 46 - 22
pandatool/src/assimp/assimpLoader.cxx

@@ -421,8 +421,7 @@ load_material(size_t index) {
 //  Description: Creates a CharacterJoint from an aiNode
 //  Description: Creates a CharacterJoint from an aiNode
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void AssimpLoader::
 void AssimpLoader::
-create_joint(Character *character, CharacterJointBundle *bundle, PartGroup *parent, const aiNode &node)
-{
+create_joint(Character *character, CharacterJointBundle *bundle, PartGroup *parent, const aiNode &node) {
   const aiMatrix4x4 &t = node.mTransformation;
   const aiMatrix4x4 &t = node.mTransformation;
   LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
   LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
                 t.a2, t.b2, t.c2, t.d2,
                 t.a2, t.b2, t.c2, t.d2,
@@ -430,6 +429,9 @@ create_joint(Character *character, CharacterJointBundle *bundle, PartGroup *pare
                 t.a4, t.b4, t.c4, t.d4);
                 t.a4, t.b4, t.c4, t.d4);
   PT(CharacterJoint) joint = new CharacterJoint(character, bundle, parent, node.mName.C_Str(), mat);
   PT(CharacterJoint) joint = new CharacterJoint(character, bundle, parent, node.mName.C_Str(), mat);
 
 
+  assimp_cat.debug()
+    << "Creating joint for: " << node.mName.C_Str() << "\n";
+
   for (size_t i = 0; i < node.mNumChildren; ++i) {
   for (size_t i = 0; i < node.mNumChildren; ++i) {
     if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
     if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
       create_joint(character, bundle, joint, *node.mChildren[i]);
       create_joint(character, bundle, joint, *node.mChildren[i]);
@@ -443,8 +445,7 @@ create_joint(Character *character, CharacterJointBundle *bundle, PartGroup *pare
 //  Description: Creates a AnimChannelMatrixXfmTable from an aiNodeAnim
 //  Description: Creates a AnimChannelMatrixXfmTable from an aiNodeAnim
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void AssimpLoader::
 void AssimpLoader::
-create_anim_channel(const aiAnimation &anim, AnimBundle *bundle, AnimGroup *parent, const aiNode &node)
-{
+create_anim_channel(const aiAnimation &anim, AnimBundle *bundle, AnimGroup *parent, const aiNode &node) {
   PT(AnimChannelMatrixXfmTable) group = new AnimChannelMatrixXfmTable(parent, node.mName.C_Str());
   PT(AnimChannelMatrixXfmTable) group = new AnimChannelMatrixXfmTable(parent, node.mName.C_Str());
 
 
   // See if there is a channel for this node
   // See if there is a channel for this node
@@ -514,7 +515,7 @@ create_anim_channel(const aiAnimation &anim, AnimBundle *bundle, AnimGroup *pare
 
 
   for (size_t i = 0; i < node.mNumChildren; ++i) {
   for (size_t i = 0; i < node.mNumChildren; ++i) {
     if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
     if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
-        create_anim_channel(anim, bundle, group, *node.mChildren[i]);
+      create_anim_channel(anim, bundle, group, *node.mChildren[i]);
     }
     }
   }
   }
 }
 }
@@ -541,17 +542,27 @@ load_mesh(size_t index) {
       _bonemap[bone.mName.C_Str()] = node;
       _bonemap[bone.mName.C_Str()] = node;
     }
     }
 
 
-    // Find the root bone node
-    const aiNode *root = _bonemap[mesh.mBones[0]->mName.C_Str()];
-    while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
-      root = root->mParent;
-    }
-
     // Now create a character from the bones
     // Now create a character from the bones
     character = new Character(mesh.mName.C_Str());
     character = new Character(mesh.mName.C_Str());
     PT(CharacterJointBundle) bundle = character->get_bundle(0);
     PT(CharacterJointBundle) bundle = character->get_bundle(0);
     PT(PartGroup) skeleton = new PartGroup(bundle, "<skeleton>");
     PT(PartGroup) skeleton = new PartGroup(bundle, "<skeleton>");
-    create_joint(character, bundle, skeleton, *root);
+
+    for (size_t i = 0; i < mesh.mNumBones; ++i) {
+      const aiBone &bone = *mesh.mBones[i];
+
+      // Find the root bone node
+      const aiNode *root = _bonemap[bone.mName.C_Str()];
+      while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
+        root = root->mParent;
+      }
+
+      // Don't process this root if we already have a joint for it
+      if (character->find_joint(root->mName.C_Str())) {
+        continue;
+      }
+
+      create_joint(character, bundle, skeleton, *root);
+    }
   }
   }
 
 
   // Create transform blend table
   // Create transform blend table
@@ -561,7 +572,11 @@ load_mesh(size_t index) {
     for (size_t i = 0; i < mesh.mNumBones; ++i) {
     for (size_t i = 0; i < mesh.mNumBones; ++i) {
       const aiBone &bone = *mesh.mBones[i];
       const aiBone &bone = *mesh.mBones[i];
       CharacterJoint *joint = character->find_joint(bone.mName.C_Str());
       CharacterJoint *joint = character->find_joint(bone.mName.C_Str());
-      nassertd(joint != NULL) continue;
+      if (joint == NULL) {
+        assimp_cat.debug()
+          << "Could not find joint for bone: " << bone.mName.C_Str() << "\n";
+        continue;
+      }
 
 
       CPT(JointVertexTransform) jvt = new JointVertexTransform(joint);
       CPT(JointVertexTransform) jvt = new JointVertexTransform(joint);
 
 
@@ -615,11 +630,6 @@ load_mesh(size_t index) {
     if (convert_anim) {
     if (convert_anim) {
       assimp_cat.debug()
       assimp_cat.debug()
         << "Found animation (" << ai_anim.mName.C_Str() << ") for character (" << mesh.mName.C_Str() << ")\n";
         << "Found animation (" << ai_anim.mName.C_Str() << ") for character (" << mesh.mName.C_Str() << ")\n";
-      // Find the root bone node
-      const aiNode *root = _bonemap[mesh.mBones[0]->mName.C_Str()];
-      while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
-        root = root->mParent;
-      }
 
 
       // Now create the animation
       // Now create the animation
       unsigned int frames = 0;
       unsigned int frames = 0;
@@ -642,11 +652,25 @@ load_mesh(size_t index) {
 
 
       PT(AnimBundle) bundle = new AnimBundle(mesh.mName.C_Str(), fps, frames);
       PT(AnimBundle) bundle = new AnimBundle(mesh.mName.C_Str(), fps, frames);
       PT(AnimGroup) skeleton = new AnimGroup(bundle, "<skeleton>");
       PT(AnimGroup) skeleton = new AnimGroup(bundle, "<skeleton>");
-      create_anim_channel(ai_anim, bundle, skeleton, *root);
 
 
-      // Attach the animation to the character node
-      PT(AnimBundleNode) bundle_node = new AnimBundleNode("anim", bundle);
-      character->add_child(bundle_node);
+      for (size_t i = 0; i < mesh.mNumBones; ++i) {
+        const aiBone &bone = *mesh.mBones[i];
+
+        // Find the root bone node
+        const aiNode *root = _bonemap[bone.mName.C_Str()];
+        while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
+          root = root->mParent;
+        }
+
+        // Only convert root nodes
+        if (root->mName == bone.mName) {
+          create_anim_channel(ai_anim, bundle, skeleton, *root);
+
+          // Attach the animation to the character node
+          PT(AnimBundleNode) bundle_node = new AnimBundleNode(bone.mName.C_Str(), bundle);
+          character->add_child(bundle_node);
+        }
+      }
     }
     }
   }
   }