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,
|
||||
// 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.
|
||||
// the skeleton must include not only the aiBones,
|
||||
// but also all their parent nodes.
|
||||
// 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
|
||||
std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
|
||||
|
||||
// note that we want to preserve input order as much as possible here.
|
||||
// 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,
|
||||
// which will be used later to mark them as type "limbNode".
|
||||
std::unordered_set<const aiNode*> limbnodes;
|
||||
|
||||
//actual bone nodes in fbx, without parenting-up
|
||||
std::unordered_set<std::string> setAllBoneNamesInScene;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
|
||||
{
|
||||
std::vector<std::string> allBoneNames;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
|
||||
aiMesh* pMesh = mScene->mMeshes[m];
|
||||
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;
|
||||
|
||||
|
@ -1902,7 +1895,7 @@ void FBXExporter::WriteObjects ()
|
|||
std::map<std::string,aiNode*> node_by_bone;
|
||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++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) {
|
||||
const aiBone* b = m->mBones[bi];
|
||||
const std::string name(b->mName.C_Str());
|
||||
|
@ -1921,7 +1914,7 @@ void FBXExporter::WriteObjects ()
|
|||
node_by_bone[name] = n;
|
||||
limbnodes.insert(n);
|
||||
}
|
||||
skeleton.insert(n);
|
||||
skeleton.push_back(n);
|
||||
// mark all parent nodes as skeleton as well,
|
||||
// up until we find the root node,
|
||||
// or else the node containing the mesh,
|
||||
|
@ -1932,7 +1925,7 @@ void FBXExporter::WriteObjects ()
|
|||
parent = parent->mParent
|
||||
) {
|
||||
// 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;
|
||||
}
|
||||
// ignore fbx transform nodes as these will be collapsed later
|
||||
|
@ -1942,7 +1935,7 @@ void FBXExporter::WriteObjects ()
|
|||
continue;
|
||||
}
|
||||
//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) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2027,7 +2020,7 @@ void FBXExporter::WriteObjects ()
|
|||
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
|
||||
|
||||
// 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) {
|
||||
// if there's a bone for this node, find it
|
||||
const aiBone* b = nullptr;
|
||||
|
|
Loading…
Reference in New Issue