Refactor global inversed matrix usage (+ minor fix)

Thanks to GreenXenith and Josiah for spotting a bug here
This commit is contained in:
Lars Mueller 2024-05-15 01:00:07 +02:00 committed by Lars Müller
parent 224066c1d3
commit d8274af670
4 changed files with 16 additions and 10 deletions

@ -159,15 +159,17 @@ public:
core::array<SWeight> Weights; core::array<SWeight> Weights;
//! Unnecessary for loaders, will be overwritten on finalize //! Unnecessary for loaders, will be overwritten on finalize
core::matrix4 GlobalMatrix; core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data.
core::matrix4 GlobalAnimatedMatrix; core::matrix4 GlobalAnimatedMatrix;
core::matrix4 LocalAnimatedMatrix; core::matrix4 LocalAnimatedMatrix;
//! These should be set by loaders.
core::vector3df Animatedposition; core::vector3df Animatedposition;
core::vector3df Animatedscale; core::vector3df Animatedscale;
core::quaternion Animatedrotation; core::quaternion Animatedrotation;
core::matrix4 GlobalInversedMatrix; // the x format pre-calculates this // The .x and .gltf formats pre-calculate this
std::optional<core::matrix4> GlobalInversedMatrix;
private: private:
//! Internal members used by CSkinnedMesh //! Internal members used by CSkinnedMesh
friend class CSkinnedMesh; friend class CSkinnedMesh;

@ -390,6 +390,7 @@ bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint)
// Transform the Vertex position by nested node... // Transform the Vertex position by nested node...
inJoint->GlobalMatrix.transformVect(Vertex.Pos); inJoint->GlobalMatrix.transformVect(Vertex.Pos);
Vertex.Normal = inJoint->GlobalMatrix.rotateAndScaleVect(Vertex.Normal); Vertex.Normal = inJoint->GlobalMatrix.rotateAndScaleVect(Vertex.Normal);
Vertex.Normal.normalize(); // renormalize: normal might have been skewed by scaling
// Add it... // Add it...
BaseVertices.push_back(Vertex); BaseVertices.push_back(Vertex);

@ -222,6 +222,7 @@ void CSkinnedMesh::buildAllLocalAnimatedMatrices()
// IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
// Not tested so far if this was correct or wrong before quaternion fix! // Not tested so far if this was correct or wrong before quaternion fix!
// Note that using getMatrix_transposed inverts the rotation.
joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix); joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix);
// --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() --- // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() ---
@ -496,8 +497,8 @@ void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint)
{ {
if (joint->Weights.size()) { if (joint->Weights.size()) {
// Find this joints pull on vertices... // Find this joints pull on vertices...
core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); // Note: It is assumed that the global inversed matrix has been calculated at this point.
jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); core::matrix4 jointVertexPull = joint->GlobalAnimatedMatrix * joint->GlobalInversedMatrix.value();
core::vector3df thisVertexMove, thisNormalMove; core::vector3df thisVertexMove, thisNormalMove;
@ -510,8 +511,10 @@ void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint)
// Pull this vertex... // Pull this vertex...
jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
if (AnimateNormals) if (AnimateNormals) {
thisNormalMove = jointVertexPull.rotateAndScaleVect(weight.StaticNormal); thisNormalMove = jointVertexPull.rotateAndScaleVect(weight.StaticNormal);
thisNormalMove.normalize(); // must renormalize after potentially scaling
}
if (!(*(weight.Moved))) { if (!(*(weight.Moved))) {
*(weight.Moved) = true; *(weight.Moved) = true;
@ -764,9 +767,9 @@ void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint)
joint->LocalAnimatedMatrix = joint->LocalMatrix; joint->LocalAnimatedMatrix = joint->LocalMatrix;
joint->GlobalAnimatedMatrix = joint->GlobalMatrix; joint->GlobalAnimatedMatrix = joint->GlobalMatrix;
if (joint->GlobalInversedMatrix.isIdentity()) { // might be pre calculated if (!joint->GlobalInversedMatrix.has_value()) { // might be pre calculated
joint->GlobalInversedMatrix = joint->GlobalMatrix; joint->GlobalInversedMatrix = joint->GlobalMatrix;
joint->GlobalInversedMatrix.makeInverse(); // slow joint->GlobalInversedMatrix->makeInverse(); // slow
} }
for (u32 j = 0; j < joint->Children.size(); ++j) for (u32 j = 0; j < joint->Children.size(); ++j)

@ -990,9 +990,9 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh)
// transforms the mesh vertices to the space of the bone // transforms the mesh vertices to the space of the bone
// When concatenated to the bone's transform, this provides the // When concatenated to the bone's transform, this provides the
// world space coordinates of the mesh as affected by the bone // world space coordinates of the mesh as affected by the bone
core::matrix4 &MatrixOffset = joint->GlobalInversedMatrix; core::matrix4 MatrixOffset;
readMatrix(MatrixOffset); readMatrix(MatrixOffset);
joint->GlobalInversedMatrix = MatrixOffset;
if (!checkForOneFollowingSemicolons()) { if (!checkForOneFollowingSemicolons()) {
os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING); os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING);