From b56cf58e337550094b6f811caa1bbec106acb7e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 16:55:04 -0800 Subject: [PATCH 1/2] Fix for mirrored transforms in FBX models extractScale will now return negative scale for left-handed matrices. --- libraries/shared/src/GLMHelpers.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index e6fbe5e5cc..257ef2f00e 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -285,7 +285,14 @@ glm::quat glmExtractRotation(const glm::mat4& matrix) { } glm::vec3 extractScale(const glm::mat4& matrix) { - return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); + glm::mat3 m(matrix); + float det = glm::determinant(m); + if (det < 0) { + // left handed matrix, flip sign to compensate. + return glm::vec3(-glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } else { + return glm::vec3(glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } } float extractUniformScale(const glm::mat4& matrix) { From 4f836568ad43ed2a0b8833fbbf35acad7f5c2f52 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 17:26:32 -0800 Subject: [PATCH 2/2] Tests to verify AnimPose decomposition is working. --- tests/animation/src/AnimTests.cpp | 91 +++++++++++++++++++++++++++---- tests/animation/src/AnimTests.h | 1 + 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 1b5bb4739a..64db3f6154 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -194,10 +194,7 @@ void AnimTests::testVariant() { auto floatVarNegative = AnimVariant(-1.0f); auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f)); auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f)); - auto mat4Var = AnimVariant(glm::mat4(glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), - glm::vec4(5.0f, 6.0f, -7.0f, 8.0f), - glm::vec4(9.0f, 10.0f, 11.0f, 12.0f), - glm::vec4(13.0f, 14.0f, 15.0f, 16.0f))); + QVERIFY(defaultVar.isBool()); QVERIFY(defaultVar.getBool() == false); @@ -232,12 +229,6 @@ void AnimTests::testVariant() { QVERIFY(q.x == 2.0f); QVERIFY(q.y == -3.0f); QVERIFY(q.z == 4.0f); - - QVERIFY(mat4Var.isMat4()); - auto m = mat4Var.getMat4(); - QVERIFY(m[0].x == 1.0f); - QVERIFY(m[1].z == -7.0f); - QVERIFY(m[3].w == 16.0f); } void AnimTests::testAccumulateTime() { @@ -323,3 +314,83 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop"); triggers.clear(); } + + +void AnimTests::testAnimPose() { + const float PI = (float)M_PI; + const glm::quat ROT_X_90 = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat ROT_Y_180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0, 0.0f)); + const glm::quat ROT_Z_30 = glm::angleAxis(PI / 6.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + std::vector scaleVec = { + glm::vec3(1), + glm::vec3(2.0f, 1.0f, 1.0f), + glm::vec3(1.0f, 0.5f, 1.0f), + glm::vec3(1.0f, 1.0f, 1.5f), + glm::vec3(2.0f, 0.5f, 1.5f), + glm::vec3(-2.0f, 0.5f, 1.5f), + glm::vec3(2.0f, -0.5f, 1.5f), + glm::vec3(2.0f, 0.5f, -1.5f), + glm::vec3(-2.0f, -0.5f, -1.5f), + }; + + std::vector rotVec = { + glm::quat(), + ROT_X_90, + ROT_Y_180, + ROT_Z_30, + ROT_X_90 * ROT_Y_180 * ROT_Z_30, + -ROT_Y_180 + }; + + std::vector transVec = { + glm::vec3(), + glm::vec3(10.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 5.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 7.5f), + glm::vec3(10.0f, 5.0f, 7.5f), + glm::vec3(-10.0f, 5.0f, 7.5f), + glm::vec3(10.0f, -5.0f, 7.5f), + glm::vec3(10.0f, 5.0f, -7.5f) + }; + + const float EPSILON = 0.001f; + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to build a matrix by parts. + AnimPose pose(scale, rot, trans); + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to decompse a matrix into parts + AnimPose pose(rawMat); + + // now build a new matrix from those parts. + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } +} diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index 7bd05369c7..a07217b91a 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -26,6 +26,7 @@ private slots: void testLoader(); void testVariant(); void testAccumulateTime(); + void testAnimPose(); }; #endif // hifi_AnimTests_h