diff --git a/AssimpToMesh/AssimpToMesh.vcxproj b/AssimpToMesh/AssimpToMesh.vcxproj
index 2c7977b..a0566f3 100644
--- a/AssimpToMesh/AssimpToMesh.vcxproj
+++ b/AssimpToMesh/AssimpToMesh.vcxproj
@@ -94,6 +94,7 @@
+
diff --git a/AssimpToMesh/AssimpToMesh.vcxproj.filters b/AssimpToMesh/AssimpToMesh.vcxproj.filters
index 7a4b7e3..ace3169 100644
--- a/AssimpToMesh/AssimpToMesh.vcxproj.filters
+++ b/AssimpToMesh/AssimpToMesh.vcxproj.filters
@@ -68,5 +68,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/AssimpToMesh/src/convert/mesh.h b/AssimpToMesh/src/convert/mesh.h
index 6778e38..a536fe5 100644
--- a/AssimpToMesh/src/convert/mesh.h
+++ b/AssimpToMesh/src/convert/mesh.h
@@ -8,6 +8,7 @@
#include "meshmaterial.h"
#include "meshtriangle.h"
#include "submesh.h"
+#include "meshjoint.h"
void WriteMeshHeader(FILE *fp);
void WriteVertices(const AssimpVertices &vertices, FILE *fp);
@@ -16,5 +17,8 @@ void WriteTexCoords(const AssimpVertices &texCoords, FILE *fp);
void WriteMaterials(const std::vector &materials, FILE *fp);
void WriteTriangles(const std::vector &triangles, FILE *fp);
void WriteSubMeshes(const std::vector &subMeshes, FILE *fp);
+void WriteJoints(const std::vector &joints, FILE *fp);
+void WriteJointToVertexMap(const std::vector &vertexToJointMap, FILE *fp);
+void WriteJointKeyFrames(const std::vector &jointKeyFrames, FILE *fp);
#endif
diff --git a/AssimpToMesh/src/convert/meshjoint.h b/AssimpToMesh/src/convert/meshjoint.h
new file mode 100644
index 0000000..194ca82
--- /dev/null
+++ b/AssimpToMesh/src/convert/meshjoint.h
@@ -0,0 +1,26 @@
+#ifndef __CONVERT_MESHJOINT_H_INCLUDED__
+#define __CONVERT_MESHJOINT_H_INCLUDED__
+
+#include
+#include
+#include
+#include
+#include
+
+struct MeshJoint
+{
+ std::string name;
+ std::string parentName;
+ aiVector3D position;
+ aiQuaternion rotation;
+};
+
+struct MeshJointKeyFrame
+{
+ aiVector3D position;
+ aiQuaternion rotation;
+};
+
+typedef std::vector JointKeyFrames;
+
+#endif
diff --git a/AssimpToMesh/src/convert/meshutils.cpp b/AssimpToMesh/src/convert/meshutils.cpp
index ceb75bb..f40717c 100644
--- a/AssimpToMesh/src/convert/meshutils.cpp
+++ b/AssimpToMesh/src/convert/meshutils.cpp
@@ -198,3 +198,105 @@ void WriteSubMeshes(const std::vector &subMeshes, FILE *fp)
fwrite(&m->numTriangles, 4, 1, fp);
}
}
+
+void WriteJoints(const std::vector &joints, FILE *fp)
+{
+ uint32_t count = joints.size();
+ if (count == 0)
+ return;
+
+ uint32_t size = 4 + // count
+ (
+ (sizeof(float) * 3) + // position (x, y, z)
+ (sizeof(float) * 4) // rotation (x, y, z, w)
+ ) * count;
+
+ // add up all the variable length joint names and parent joint names
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ size += joints[i].name.length() + 1; // include null terminator
+ size += joints[i].name.length() + 1; // ditto
+ }
+
+ fputs("JNT", fp);
+ fwrite(&size, 4, 1, fp);
+ fwrite(&count, 4, 1, fp);
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ const MeshJoint *j = &joints[i];
+
+ fwrite(j->name.c_str(), j->name.length(), 1, fp);
+ char c = '\0';
+ fwrite(&c, 1, 1, fp);
+
+ // haven't tried, but i have a feeling fwrite() won't like passing a length of 0 to be written
+ if (j->parentName.length() > 0)
+ fwrite(j->parentName.c_str(), j->parentName.length(), 1, fp);
+ fwrite(&c, 1, 1, fp);
+
+ fwrite(&j->position.x, sizeof(float), 1, fp);
+ fwrite(&j->position.y, sizeof(float), 1, fp);
+ fwrite(&j->position.z, sizeof(float), 1, fp);
+
+ fwrite(&j->rotation.x, sizeof(float), 1, fp);
+ fwrite(&j->rotation.y, sizeof(float), 1, fp);
+ fwrite(&j->rotation.z, sizeof(float), 1, fp);
+ fwrite(&j->rotation.w, sizeof(float), 1, fp);
+ }
+}
+
+void WriteJointToVertexMap(const std::vector &vertexToJointMap, FILE *fp)
+{
+ uint32_t count = vertexToJointMap.size();
+ if (count == 0)
+ return;
+
+ uint32_t size = 4 + // count
+ (4 * count); // num vertices
+
+ fputs("JTV", fp);
+ fwrite(&size, 4, 1, fp);
+ fwrite(&count, 4, 1, fp);
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ uint32_t jointIndex = vertexToJointMap[i];
+ fwrite(&jointIndex, 4, 1, fp);
+ }
+}
+
+void WriteJointKeyFrames(const std::vector &jointKeyFrames, FILE *fp)
+{
+ uint32_t numJoints = jointKeyFrames.size();
+ if (numJoints == 0)
+ return;
+
+ uint32_t numFrames = jointKeyFrames[0].size();
+
+ uint32_t size = 4 + // num frames
+ (
+ (
+ (sizeof(float) * 3) + // position (x, y, z)
+ (sizeof(float) * 4) // rotation (x, y, z, w)
+ ) * numJoints // for each joint
+ ) * numFrames; // for each frame
+
+ fputs("JKF", fp);
+ fwrite(&size, 4, 1, fp);
+ fwrite(&numFrames, 4, 1, fp);
+ for (uint32_t i = 0; i < numJoints; ++i)
+ {
+ for (uint32_t j = 0; j < numFrames; ++j)
+ {
+ const MeshJointKeyFrame *frame = &jointKeyFrames[i][j];
+
+ fwrite(&frame->position.x, sizeof(float), 1, fp);
+ fwrite(&frame->position.y, sizeof(float), 1, fp);
+ fwrite(&frame->position.z, sizeof(float), 1, fp);
+
+ fwrite(&frame->rotation.x, sizeof(float), 1, fp);
+ fwrite(&frame->rotation.y, sizeof(float), 1, fp);
+ fwrite(&frame->rotation.z, sizeof(float), 1, fp);
+ fwrite(&frame->rotation.w, sizeof(float), 1, fp);
+ }
+ }
+}
diff --git a/AssimpToMesh/src/convert/skeletalanimated.cpp b/AssimpToMesh/src/convert/skeletalanimated.cpp
index 1b31a2a..6a7b98d 100644
--- a/AssimpToMesh/src/convert/skeletalanimated.cpp
+++ b/AssimpToMesh/src/convert/skeletalanimated.cpp
@@ -69,29 +69,76 @@ void ConvertSkeletalAnimated(const std::string &outfile, const aiScene *scene)
}
WriteSubMeshes(subMeshes, fp);
- // joints
- // foreach joint:
- // - name
- // - parentindex (or name?)
- // - position (vec3d)
- // - rotation (vec3d or quat?)
+ // TODO: cheating for now, but according to the ASSIMP doc's, there could be
+ // models which have nodes that are not used by any bones, but still
+ // affect the skeleton pose, because child nodes *are* used by bones
+ // and so, any parent node transformations will apply and need to be
+ // carried down the chain. None of the test models I'm using have this
+ // type of node structure, so I'm ignoring it for now :)
- // joints to vertices mapping
- // foreach vertex:
- // - jointindex
- // - weight
+ // collect basic skeleton/joint info
+ std::vector joints;
+ std::vector vertexToJointMap;
+ vertexToJointMap.resize(vertices.size());
+ for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
+ {
+ aiMesh *mesh = scene->mMeshes[i];
+ for (unsigned int j = 0; j < mesh->mNumBones; ++j)
+ {
+ aiBone *bone = mesh->mBones[j];
+ aiNode *node = scene->mRootNode->FindNode(bone->mName);
+ aiNode *parentNode = node->mParent;
- // joint keyframes
- // foreach keyframe:
- // foreach joint:
- // - position (vec3d)
- // - rotation (vec3d or quat?)
+ MeshJoint joint;
+ joint.name = std::string(bone->mName.data, bone->mName.length);
+ if (strcmp(parentNode->mName.data, "$dummy_root") == 0)
+ joint.parentName = "";
+ else
+ joint.parentName = std::string(parentNode->mName.data, parentNode->mName.length);
+ node->mTransformation.DecomposeNoScaling(joint.rotation, joint.position);
- // animation sequences
- // foreach sequence:
- // - name
- // - start frame index
- // - end frame index
+ // assumption: sum of all bone->mNumWeights is always == vertices.size()
+ for (unsigned int k = 0; k < bone->mNumWeights; ++k)
+ {
+ aiVertexWeight *weight = &bone->mWeights[k];
+ unsigned int index = vertexIndicesMap[i][weight->mVertexId];
+ vertexToJointMap[index] = j;
+ }
+
+ joints.push_back(joint);
+ }
+ }
+ WriteJoints(joints, fp);
+ WriteJointToVertexMap(vertexToJointMap, fp);
+
+ // TODO: this collection process is dumb at the moment. assumes each bone
+ // has the same number of frames as all the other ones. also, every
+ // test model i've used so far puts all the frames into a single
+ // animation (usually without a name even). so this is, for now, only
+ // looking at the first aiAnimation object. ALSO, because i'm REALLY
+ // lazy, the animations aiNodeAnim objects are assumed to be in the
+ // same order as the bones were collected in :)
+ // collect joint keyframes
+ std::vector meshFrames;
+ aiAnimation *animation = scene->mAnimations[0];
+ for (unsigned int i = 0; i < animation->mNumChannels; ++i)
+ {
+ aiNodeAnim *nodeAnim = animation->mChannels[i];
+ JointKeyFrames jointFrames;
+
+ for (unsigned int j = 0; j < nodeAnim->mNumPositionKeys; ++j)
+ {
+ // TODO: should really get the times too
+ MeshJointKeyFrame frame;
+ frame.position = nodeAnim->mPositionKeys[j].mValue;
+ frame.rotation = nodeAnim->mRotationKeys[j].mValue;
+
+ jointFrames.push_back(frame);
+ }
+
+ meshFrames.push_back(jointFrames);
+ }
+ WriteJointKeyFrames(meshFrames, fp);
fclose(fp);
}