Merge pull request #2585 from RevoluPowered/feature/fix-armature-and-root-node
FBX importer armature fixes and root bone fixes - animations should now work for more models.pull/2574/head^2
commit
1097f47ff5
|
@ -90,7 +90,6 @@ namespace Assimp {
|
||||||
, anim_fps()
|
, anim_fps()
|
||||||
, out(out)
|
, out(out)
|
||||||
, doc(doc)
|
, doc(doc)
|
||||||
, mRemoveEmptyBones( removeEmptyBones )
|
|
||||||
, mCurrentUnit(FbxUnit::cm) {
|
, mCurrentUnit(FbxUnit::cm) {
|
||||||
// animations need to be converted first since this will
|
// animations need to be converted first since this will
|
||||||
// populate the node_anim_chain_bits map, which is needed
|
// populate the node_anim_chain_bits map, which is needed
|
||||||
|
@ -1462,14 +1461,8 @@ namespace Assimp {
|
||||||
|
|
||||||
const WeightIndexArray& indices = cluster->GetIndices();
|
const WeightIndexArray& indices = cluster->GetIndices();
|
||||||
|
|
||||||
if (indices.empty() && mRemoveEmptyBones ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MatIndexArray& mats = geo.GetMaterialIndices();
|
const MatIndexArray& mats = geo.GetMaterialIndices();
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||||
|
|
||||||
count_out_indices.clear();
|
count_out_indices.clear();
|
||||||
|
@ -1509,8 +1502,7 @@ namespace Assimp {
|
||||||
out_indices.push_back(std::distance(outputVertStartIndices->begin(), it));
|
out_indices.push_back(std::distance(outputVertStartIndices->begin(), it));
|
||||||
}
|
}
|
||||||
|
|
||||||
++count_out_indices.back();
|
++count_out_indices.back();
|
||||||
ok = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1518,10 +1510,8 @@ namespace Assimp {
|
||||||
// if we found at least one, generate the output bones
|
// if we found at least one, generate the output bones
|
||||||
// XXX this could be heavily simplified by collecting the bone
|
// XXX this could be heavily simplified by collecting the bone
|
||||||
// data in a single step.
|
// data in a single step.
|
||||||
if (ok && mRemoveEmptyBones) {
|
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
|
||||||
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
|
|
||||||
count_out_indices, node_global_transform);
|
count_out_indices, node_global_transform);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception&) {
|
catch (std::exception&) {
|
||||||
|
|
|
@ -470,9 +470,6 @@ private:
|
||||||
|
|
||||||
aiScene* const out;
|
aiScene* const out;
|
||||||
const FBX::Document& doc;
|
const FBX::Document& doc;
|
||||||
|
|
||||||
bool mRemoveEmptyBones;
|
|
||||||
|
|
||||||
FbxUnit mCurrentUnit;
|
FbxUnit mCurrentUnit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,14 +90,6 @@ const Object* LazyObject::Get(bool dieOnError)
|
||||||
return object.get();
|
return object.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is the root object, we return a dummy since there
|
|
||||||
// is no root object int he fbx file - it is just referenced
|
|
||||||
// with id 0.
|
|
||||||
if(id == 0L) {
|
|
||||||
object.reset(new Object(id, element, "Model::RootNode"));
|
|
||||||
return object.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token& key = element.KeyToken();
|
const Token& key = element.KeyToken();
|
||||||
const TokenList& tokens = element.Tokens();
|
const TokenList& tokens = element.Tokens();
|
||||||
|
|
||||||
|
|
|
@ -1706,8 +1706,7 @@ void FBXExporter::WriteObjects ()
|
||||||
}
|
}
|
||||||
if (end) { break; }
|
if (end) { break; }
|
||||||
}
|
}
|
||||||
limbnodes.insert(parent);
|
|
||||||
skeleton.insert(parent);
|
|
||||||
// if it was the skeleton root we can finish here
|
// if it was the skeleton root we can finish here
|
||||||
if (end) { break; }
|
if (end) { break; }
|
||||||
}
|
}
|
||||||
|
@ -1848,46 +1847,10 @@ void FBXExporter::WriteObjects ()
|
||||||
inverse_bone_xform.Inverse();
|
inverse_bone_xform.Inverse();
|
||||||
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
|
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
|
||||||
|
|
||||||
// this should be the same as the bone's mOffsetMatrix.
|
sdnode.AddChild("Transform", tr);
|
||||||
// if it's not the same, the skeleton isn't in the bind pose.
|
|
||||||
float epsilon = 1e-4f; // some error is to be expected
|
|
||||||
float epsilon_custom = mProperties->GetPropertyFloat("BINDPOSE_EPSILON", -1);
|
|
||||||
if(epsilon_custom > 0) {
|
|
||||||
epsilon = epsilon_custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bone_xform_okay = true;
|
|
||||||
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
|
|
||||||
not_in_bind_pose.insert(b);
|
|
||||||
bone_xform_okay = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have a bone we should use the mOffsetMatrix,
|
|
||||||
// otherwise try to just use the calculated transform.
|
|
||||||
if (b) {
|
|
||||||
sdnode.AddChild("Transform", b->mOffsetMatrix);
|
|
||||||
} else {
|
|
||||||
sdnode.AddChild("Transform", tr);
|
|
||||||
}
|
|
||||||
// note: it doesn't matter if we mix these,
|
|
||||||
// because if they disagree we'll throw an exception later.
|
|
||||||
// it could be that the skeleton is not in the bone pose
|
|
||||||
// but all bones are still defined,
|
|
||||||
// in which case this would use the mOffsetMatrix for everything
|
|
||||||
// and a correct skeleton would still be output.
|
|
||||||
|
|
||||||
// transformlink should be the position of the bone in world space.
|
sdnode.AddChild("TransformLink", bone_xform);
|
||||||
// if the bone is in the bind pose (or nonexistent),
|
|
||||||
// we can just use the matrix we already calculated
|
|
||||||
if (bone_xform_okay) {
|
|
||||||
sdnode.AddChild("TransformLink", bone_xform);
|
|
||||||
// otherwise we can only work it out using the mesh position.
|
|
||||||
} else {
|
|
||||||
aiMatrix4x4 trl = b->mOffsetMatrix;
|
|
||||||
trl.Inverse();
|
|
||||||
trl *= mesh_xform;
|
|
||||||
sdnode.AddChild("TransformLink", trl);
|
|
||||||
}
|
|
||||||
// note: this means we ALWAYS rely on the mesh node transform
|
// note: this means we ALWAYS rely on the mesh node transform
|
||||||
// being unchanged from the time the skeleton was bound.
|
// being unchanged from the time the skeleton was bound.
|
||||||
// there's not really any way around this at the moment.
|
// there's not really any way around this at the moment.
|
||||||
|
|
|
@ -115,7 +115,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
|
|
||||||
if(tempVerts.empty()) {
|
if(tempVerts.empty()) {
|
||||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> tempFaces;
|
std::vector<int> tempFaces;
|
||||||
|
@ -123,7 +122,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
||||||
|
|
||||||
if(tempFaces.empty()) {
|
if(tempFaces.empty()) {
|
||||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vertices.reserve(tempFaces.size());
|
m_vertices.reserve(tempFaces.size());
|
||||||
|
|
Loading…
Reference in New Issue