Fix exporting incorrect bone order (#5435)
Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>pull/5645/head
parent
cdf8394ccc
commit
d0703a5a3a
|
@ -1868,33 +1868,26 @@ void FBXExporter::WriteObjects ()
|
||||||
// one sticky point is that the number of vertices may not match,
|
// one sticky point is that the number of vertices may not match,
|
||||||
// because assimp splits vertices by normal, uv, etc.
|
// because assimp splits vertices by normal, uv, etc.
|
||||||
|
|
||||||
// functor for aiNode sorting
|
|
||||||
struct SortNodeByName
|
|
||||||
{
|
|
||||||
bool operator()(const aiNode *lhs, const aiNode *rhs) const
|
|
||||||
{
|
|
||||||
return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// first we should mark the skeleton for each mesh.
|
// first we should mark the skeleton for each mesh.
|
||||||
// the skeleton must include not only the aiBones,
|
// the skeleton must include not only the aiBones,
|
||||||
// but also all their parent nodes.
|
// but also all their parent nodes.
|
||||||
// anything that affects the position of any bone node must be included.
|
// anything that affects the position of any bone node must be included.
|
||||||
// Use SorNodeByName to make sure the exported result will be the same across all systems
|
|
||||||
// Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent
|
// note that we want to preserve input order as much as possible here.
|
||||||
std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
|
// previously, sorting by name lead to consistent output across systems, but was not
|
||||||
|
// suitable for downstream consumption by some applications.
|
||||||
|
std::vector<std::vector<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
|
||||||
// at the same time we can build a list of all the skeleton nodes,
|
// at the same time we can build a list of all the skeleton nodes,
|
||||||
// which will be used later to mark them as type "limbNode".
|
// which will be used later to mark them as type "limbNode".
|
||||||
std::unordered_set<const aiNode*> limbnodes;
|
std::unordered_set<const aiNode*> limbnodes;
|
||||||
|
|
||||||
//actual bone nodes in fbx, without parenting-up
|
//actual bone nodes in fbx, without parenting-up
|
||||||
std::unordered_set<std::string> setAllBoneNamesInScene;
|
std::vector<std::string> allBoneNames;
|
||||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
|
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
|
||||||
{
|
|
||||||
aiMesh* pMesh = mScene->mMeshes[m];
|
aiMesh* pMesh = mScene->mMeshes[m];
|
||||||
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
|
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
|
||||||
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
|
allBoneNames.push_back(pMesh->mBones[b]->mName.data);
|
||||||
}
|
}
|
||||||
aiMatrix4x4 mxTransIdentity;
|
aiMatrix4x4 mxTransIdentity;
|
||||||
|
|
||||||
|
@ -1902,7 +1895,7 @@ void FBXExporter::WriteObjects ()
|
||||||
std::map<std::string,aiNode*> node_by_bone;
|
std::map<std::string,aiNode*> node_by_bone;
|
||||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
||||||
const aiMesh* m = mScene->mMeshes[mi];
|
const aiMesh* m = mScene->mMeshes[mi];
|
||||||
std::set<const aiNode*, SortNodeByName> skeleton;
|
std::vector<const aiNode*> skeleton;
|
||||||
for (size_t bi =0; bi < m->mNumBones; ++bi) {
|
for (size_t bi =0; bi < m->mNumBones; ++bi) {
|
||||||
const aiBone* b = m->mBones[bi];
|
const aiBone* b = m->mBones[bi];
|
||||||
const std::string name(b->mName.C_Str());
|
const std::string name(b->mName.C_Str());
|
||||||
|
@ -1921,7 +1914,7 @@ void FBXExporter::WriteObjects ()
|
||||||
node_by_bone[name] = n;
|
node_by_bone[name] = n;
|
||||||
limbnodes.insert(n);
|
limbnodes.insert(n);
|
||||||
}
|
}
|
||||||
skeleton.insert(n);
|
skeleton.push_back(n);
|
||||||
// mark all parent nodes as skeleton as well,
|
// mark all parent nodes as skeleton as well,
|
||||||
// up until we find the root node,
|
// up until we find the root node,
|
||||||
// or else the node containing the mesh,
|
// or else the node containing the mesh,
|
||||||
|
@ -1932,7 +1925,7 @@ void FBXExporter::WriteObjects ()
|
||||||
parent = parent->mParent
|
parent = parent->mParent
|
||||||
) {
|
) {
|
||||||
// if we've already done this node we can skip it all
|
// if we've already done this node we can skip it all
|
||||||
if (skeleton.count(parent)) {
|
if (std::find(skeleton.begin(), skeleton.end(), parent) != skeleton.end()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// ignore fbx transform nodes as these will be collapsed later
|
// ignore fbx transform nodes as these will be collapsed later
|
||||||
|
@ -1942,7 +1935,7 @@ void FBXExporter::WriteObjects ()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//not a bone in scene && no effect in transform
|
//not a bone in scene && no effect in transform
|
||||||
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
|
if (std::find(allBoneNames.begin(), allBoneNames.end(), node_name) == allBoneNames.end()
|
||||||
&& parent->mTransformation == mxTransIdentity) {
|
&& parent->mTransformation == mxTransIdentity) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2027,7 +2020,7 @@ void FBXExporter::WriteObjects ()
|
||||||
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
|
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
|
||||||
|
|
||||||
// now make a subdeformer for each bone in the skeleton
|
// now make a subdeformer for each bone in the skeleton
|
||||||
const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi];
|
const auto & skeleton= skeleton_by_mesh[mi];
|
||||||
for (const aiNode* bone_node : skeleton) {
|
for (const aiNode* bone_node : skeleton) {
|
||||||
// if there's a bone for this node, find it
|
// if there's a bone for this node, find it
|
||||||
const aiBone* b = nullptr;
|
const aiBone* b = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue