commit
5cd16a0aa6
|
@ -811,6 +811,8 @@ namespace glTF
|
||||||
Ref<Skin> skin; //!< The ID of the skin referenced by this node.
|
Ref<Skin> skin; //!< The ID of the skin referenced by this node.
|
||||||
std::string jointName; //!< Name used when this node is a joint in a skin.
|
std::string jointName; //!< Name used when this node is a joint in a skin.
|
||||||
|
|
||||||
|
Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
|
||||||
|
|
||||||
Node() {}
|
Node() {}
|
||||||
void Read(Value& obj, Asset& r);
|
void Read(Value& obj, Asset& r);
|
||||||
};
|
};
|
||||||
|
|
|
@ -132,7 +132,7 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
|
||||||
ExportMaterials();
|
ExportMaterials();
|
||||||
|
|
||||||
if (mScene->mRootNode) {
|
if (mScene->mRootNode) {
|
||||||
ExportNode(mScene->mRootNode);
|
ExportNodeHierarchy(mScene->mRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportMeshes();
|
ExportMeshes();
|
||||||
|
@ -164,6 +164,14 @@ static void CopyValue(const aiMatrix4x4& v, glTF::mat4& o)
|
||||||
o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
|
o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CopyValue(const aiMatrix4x4& v, aiMatrix4x4& o)
|
||||||
|
{
|
||||||
|
o.a1 = v.a1; o.a2 = v.a2; o.a3 = v.a3; o.a4 = v.a4;
|
||||||
|
o.b1 = v.b1; o.b2 = v.b2; o.b3 = v.b3; o.b4 = v.b4;
|
||||||
|
o.c1 = v.c1; o.c2 = v.c2; o.c3 = v.c3; o.c4 = v.c4;
|
||||||
|
o.d1 = v.d1; o.d2 = v.d2; o.d3 = v.d3; o.d4 = v.d4;
|
||||||
|
}
|
||||||
|
|
||||||
static void IdentityMatrix4(glTF::mat4& o)
|
static void IdentityMatrix4(glTF::mat4& o)
|
||||||
{
|
{
|
||||||
o[ 0] = 1; o[ 1] = 0; o[ 2] = 0; o[ 3] = 0;
|
o[ 0] = 1; o[ 1] = 0; o[ 2] = 0; o[ 3] = 0;
|
||||||
|
@ -390,50 +398,37 @@ bool FindMeshNode(Ref<Node>& nodeIn, Ref<Node>& meshNode, std::string meshID)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the root joint of the skeleton.
|
* Find the root joint of the skeleton.
|
||||||
|
* Starts will any joint node and traces up the tree,
|
||||||
|
* until a parent is found that does not have a jointName.
|
||||||
|
* Returns the first parent Ref<Node> found that does not have a jointName.
|
||||||
*/
|
*/
|
||||||
Ref<Node> FindSkeletonRootJoint(Ref<Skin>& skinRef)
|
Ref<Node> FindSkeletonRootJoint(Ref<Skin>& skinRef)
|
||||||
{
|
{
|
||||||
Ref<Node> candidateNodeRef;
|
Ref<Node> startNodeRef;
|
||||||
Ref<Node> testNodeRef;
|
Ref<Node> parentNodeRef;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < skinRef->jointNames.size(); ++i) {
|
// Arbitrarily use the first joint to start the search.
|
||||||
candidateNodeRef = skinRef->jointNames[i];
|
startNodeRef = skinRef->jointNames[0];
|
||||||
bool candidateIsRoot = true;
|
parentNodeRef = skinRef->jointNames[0];
|
||||||
|
|
||||||
for (unsigned int j = 0; j < skinRef->jointNames.size(); ++j) {
|
do {
|
||||||
if (i == j) continue;
|
startNodeRef = parentNodeRef;
|
||||||
|
parentNodeRef = startNodeRef->parent;
|
||||||
|
} while (!parentNodeRef->jointName.empty());
|
||||||
|
|
||||||
testNodeRef = skinRef->jointNames[j];
|
return parentNodeRef;
|
||||||
for (unsigned int k = 0; k < testNodeRef->children.size(); ++k) {
|
|
||||||
std::string childNodeRefID = testNodeRef->children[k]->id;
|
|
||||||
|
|
||||||
if (childNodeRefID.compare(candidateNodeRef->id) == 0) {
|
|
||||||
candidateIsRoot = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(candidateIsRoot == true) {
|
|
||||||
return candidateNodeRef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return candidateNodeRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref<Mesh>& meshRef, Ref<Buffer>& bufferRef)
|
void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref<Mesh>& meshRef, Ref<Buffer>& bufferRef, Ref<Skin>& skinRef, std::vector<aiMatrix4x4>& inverseBindMatricesData)
|
||||||
{
|
{
|
||||||
std::string skinName = aim->mName.C_Str();
|
if (aim->mNumBones < 1) {
|
||||||
skinName = mAsset.FindUniqueID(skinName, "skin");
|
return;
|
||||||
Ref<Skin> skinRef = mAsset.skins.Create(skinName);
|
}
|
||||||
skinRef->name = skinName;
|
|
||||||
|
|
||||||
mat4* inverseBindMatricesData = new mat4[aim->mNumBones];
|
|
||||||
|
|
||||||
// Store the vertex joint and weight data.
|
// Store the vertex joint and weight data.
|
||||||
vec4* vertexJointData = new vec4[aim->mNumVertices];
|
vec4* vertexJointData = new vec4[aim->mNumVertices];
|
||||||
vec4* vertexWeightData = new vec4[aim->mNumVertices];
|
vec4* vertexWeightData = new vec4[aim->mNumVertices];
|
||||||
unsigned int* jointsPerVertex = new unsigned int[aim->mNumVertices];
|
int* jointsPerVertex = new int[aim->mNumVertices];
|
||||||
for (size_t i = 0; i < aim->mNumVertices; ++i) {
|
for (size_t i = 0; i < aim->mNumVertices; ++i) {
|
||||||
jointsPerVertex[i] = 0;
|
jointsPerVertex[i] = 0;
|
||||||
for (size_t j = 0; j < 4; ++j) {
|
for (size_t j = 0; j < 4; ++j) {
|
||||||
|
@ -448,49 +443,49 @@ void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref<Mesh>& meshRef, Ref<Buffer
|
||||||
// aib->mName =====> skinRef->jointNames
|
// aib->mName =====> skinRef->jointNames
|
||||||
// Find the node with id = mName.
|
// Find the node with id = mName.
|
||||||
Ref<Node> nodeRef = mAsset.nodes.Get(aib->mName.C_Str());
|
Ref<Node> nodeRef = mAsset.nodes.Get(aib->mName.C_Str());
|
||||||
nodeRef->jointName = "joint_" + to_string(idx_bone);
|
nodeRef->jointName = nodeRef->id;
|
||||||
skinRef->jointNames.push_back(nodeRef);
|
|
||||||
|
|
||||||
// Identity Matrix =====> skinRef->bindShapeMatrix
|
unsigned int jointNamesIndex;
|
||||||
// Temporary. Hard-coded identity matrix here
|
bool addJointToJointNames = true;
|
||||||
skinRef->bindShapeMatrix.isPresent = true;
|
for (int idx_joint = 0; idx_joint < skinRef->jointNames.size(); ++idx_joint) {
|
||||||
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
if (skinRef->jointNames[idx_joint]->jointName.compare(nodeRef->jointName) == 0) {
|
||||||
|
addJointToJointNames = false;
|
||||||
|
jointNamesIndex = idx_joint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// aib->mOffsetMatrix =====> skinRef->inverseBindMatrices
|
if (addJointToJointNames) {
|
||||||
CopyValue(aib->mOffsetMatrix, inverseBindMatricesData[idx_bone]);
|
skinRef->jointNames.push_back(nodeRef);
|
||||||
|
|
||||||
|
// aib->mOffsetMatrix =====> skinRef->inverseBindMatrices
|
||||||
|
aiMatrix4x4 tmpMatrix4;
|
||||||
|
CopyValue(aib->mOffsetMatrix, tmpMatrix4);
|
||||||
|
inverseBindMatricesData.push_back(tmpMatrix4);
|
||||||
|
jointNamesIndex = inverseBindMatricesData.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// aib->mWeights =====> vertexWeightData
|
// aib->mWeights =====> vertexWeightData
|
||||||
for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) {
|
for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) {
|
||||||
aiVertexWeight tmpVertWeight = aib->mWeights[idx_weights];
|
unsigned int vertexId = aib->mWeights[idx_weights].mVertexId;
|
||||||
vertexJointData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = idx_bone;
|
float vertWeight = aib->mWeights[idx_weights].mWeight;
|
||||||
vertexWeightData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = tmpVertWeight.mWeight;
|
|
||||||
|
|
||||||
jointsPerVertex[tmpVertWeight.mVertexId] += 1;
|
// A vertex can only have at most four joint weights. Ignore all others.
|
||||||
|
if (jointsPerVertex[vertexId] > 3) { continue; }
|
||||||
|
|
||||||
|
vertexJointData[vertexId][jointsPerVertex[vertexId]] = jointNamesIndex;
|
||||||
|
vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight;
|
||||||
|
|
||||||
|
jointsPerVertex[vertexId] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End: for-loop mNumMeshes
|
} // End: for-loop mNumMeshes
|
||||||
|
|
||||||
// Create the Accessor for skinRef->inverseBindMatrices
|
|
||||||
Ref<Accessor> invBindMatrixAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumBones, inverseBindMatricesData, AttribType::MAT4, AttribType::MAT4, ComponentType_FLOAT);
|
|
||||||
if (invBindMatrixAccessor) skinRef->inverseBindMatrices = invBindMatrixAccessor;
|
|
||||||
|
|
||||||
|
|
||||||
Mesh::Primitive& p = meshRef->primitives.back();
|
Mesh::Primitive& p = meshRef->primitives.back();
|
||||||
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aim->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||||
if (vertexJointAccessor) p.attributes.joint.push_back(vertexJointAccessor);
|
if (vertexJointAccessor) p.attributes.joint.push_back(vertexJointAccessor);
|
||||||
|
|
||||||
Ref<Accessor> vertexWeightAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumVertices, vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
Ref<Accessor> vertexWeightAccessor = ExportData(mAsset, skinRef->id, bufferRef, aim->mNumVertices, vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||||
if (vertexWeightAccessor) p.attributes.weight.push_back(vertexWeightAccessor);
|
if (vertexWeightAccessor) p.attributes.weight.push_back(vertexWeightAccessor);
|
||||||
|
|
||||||
|
|
||||||
// Find node that contains this mesh and add "skeletons" and "skin" attributes to that node.
|
|
||||||
Ref<Node> rootNode = mAsset.nodes.Get(unsigned(0));
|
|
||||||
Ref<Node> meshNode;
|
|
||||||
FindMeshNode(rootNode, meshNode, meshRef->id);
|
|
||||||
|
|
||||||
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
|
|
||||||
meshNode->skeletons.push_back(rootJoint);
|
|
||||||
meshNode->skin = skinRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void glTFExporter::ExportMeshes()
|
void glTFExporter::ExportMeshes()
|
||||||
|
@ -520,6 +515,26 @@ void glTFExporter::ExportMeshes()
|
||||||
b = mAsset->buffers.Create(bufferId);
|
b = mAsset->buffers.Create(bufferId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// Initialize variables for the skin
|
||||||
|
bool createSkin = false;
|
||||||
|
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
||||||
|
const aiMesh* aim = mScene->mMeshes[idx_mesh];
|
||||||
|
if(aim->HasBones()) {
|
||||||
|
createSkin = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Skin> skinRef;
|
||||||
|
std::string skinName = mAsset->FindUniqueID("skin", "skin");
|
||||||
|
std::vector<aiMatrix4x4> inverseBindMatricesData;
|
||||||
|
if(createSkin) {
|
||||||
|
skinRef = mAsset->skins.Create(skinName);
|
||||||
|
skinRef->name = skinName;
|
||||||
|
}
|
||||||
|
//----------------------------------------
|
||||||
|
|
||||||
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
||||||
const aiMesh* aim = mScene->mMeshes[idx_mesh];
|
const aiMesh* aim = mScene->mMeshes[idx_mesh];
|
||||||
|
|
||||||
|
@ -616,7 +631,7 @@ void glTFExporter::ExportMeshes()
|
||||||
|
|
||||||
/*************** Skins ****************/
|
/*************** Skins ****************/
|
||||||
if(aim->HasBones()) {
|
if(aim->HasBones()) {
|
||||||
ExportSkin(*mAsset, aim, m, b);
|
ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************** Compression ******************/
|
/****************** Compression ******************/
|
||||||
|
@ -711,9 +726,41 @@ void glTFExporter::ExportMeshes()
|
||||||
#endif
|
#endif
|
||||||
}// if(comp_allow)
|
}// if(comp_allow)
|
||||||
}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i)
|
}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i)
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
// Finish the skin
|
||||||
|
// Create the Accessor for skinRef->inverseBindMatrices
|
||||||
|
if (createSkin) {
|
||||||
|
mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()];
|
||||||
|
for (int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
|
||||||
|
CopyValue(inverseBindMatricesData[idx_joint], invBindMatrixData[idx_joint]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> invBindMatrixAccessor = ExportData(*mAsset, skinName, b, inverseBindMatricesData.size(), invBindMatrixData, AttribType::MAT4, AttribType::MAT4, ComponentType_FLOAT);
|
||||||
|
if (invBindMatrixAccessor) skinRef->inverseBindMatrices = invBindMatrixAccessor;
|
||||||
|
|
||||||
|
// Identity Matrix =====> skinRef->bindShapeMatrix
|
||||||
|
// Temporary. Hard-coded identity matrix here
|
||||||
|
skinRef->bindShapeMatrix.isPresent = true;
|
||||||
|
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
||||||
|
|
||||||
|
// Find node that contains this mesh and add "skeletons" and "skin" attributes to that node.
|
||||||
|
Ref<Node> rootNode = mAsset->nodes.Get(unsigned(0));
|
||||||
|
Ref<Node> meshNode;
|
||||||
|
std::string meshID = mAsset->meshes.Get(unsigned(0))->id;
|
||||||
|
FindMeshNode(rootNode, meshNode, meshID);
|
||||||
|
|
||||||
|
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
|
||||||
|
meshNode->skeletons.push_back(rootJoint);
|
||||||
|
meshNode->skin = skinRef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int glTFExporter::ExportNode(const aiNode* n)
|
/*
|
||||||
|
* Export the root node of the node hierarchy.
|
||||||
|
* Calls ExportNode for all children.
|
||||||
|
*/
|
||||||
|
unsigned int glTFExporter::ExportNodeHierarchy(const aiNode* n)
|
||||||
{
|
{
|
||||||
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
|
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
|
||||||
|
|
||||||
|
@ -727,7 +774,34 @@ unsigned int glTFExporter::ExportNode(const aiNode* n)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||||
unsigned int idx = ExportNode(n->mChildren[i]);
|
unsigned int idx = ExportNode(n->mChildren[i], node);
|
||||||
|
node->children.push_back(mAsset->nodes.Get(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.GetIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Export node and recursively calls ExportNode for all children.
|
||||||
|
* Since these nodes are not the root node, we also export the parent Ref<Node>
|
||||||
|
*/
|
||||||
|
unsigned int glTFExporter::ExportNode(const aiNode* n, Ref<Node>& parent)
|
||||||
|
{
|
||||||
|
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
|
||||||
|
|
||||||
|
node->parent = parent;
|
||||||
|
|
||||||
|
if (!n->mTransformation.IsIdentity()) {
|
||||||
|
node->matrix.isPresent = true;
|
||||||
|
CopyValue(n->mTransformation, node->matrix.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||||
|
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||||
|
unsigned int idx = ExportNode(n->mChildren[i], node);
|
||||||
node->children.push_back(mAsset->nodes.Get(idx));
|
node->children.push_back(mAsset->nodes.Get(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,12 @@ struct aiMaterial;
|
||||||
|
|
||||||
namespace glTF
|
namespace glTF
|
||||||
{
|
{
|
||||||
|
template<class T>
|
||||||
|
class Ref;
|
||||||
|
|
||||||
class Asset;
|
class Asset;
|
||||||
struct TexProperty;
|
struct TexProperty;
|
||||||
|
struct Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
|
@ -98,7 +102,8 @@ namespace Assimp
|
||||||
void ExportMetadata();
|
void ExportMetadata();
|
||||||
void ExportMaterials();
|
void ExportMaterials();
|
||||||
void ExportMeshes();
|
void ExportMeshes();
|
||||||
unsigned int ExportNode(const aiNode* node);
|
unsigned int ExportNodeHierarchy(const aiNode* n);
|
||||||
|
unsigned int ExportNode(const aiNode* node, glTF::Ref<glTF::Node>& parent);
|
||||||
void ExportScene();
|
void ExportScene();
|
||||||
void ExportAnimations();
|
void ExportAnimations();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue