From 347104204e40ff2f2939ea67db3f36f2128f4e51 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 09:56:39 -0700 Subject: [PATCH 1/7] fix StorageTests on linux --- tests/shared/src/StorageTests.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/shared/src/StorageTests.cpp b/tests/shared/src/StorageTests.cpp index fa538f6911..48e6b91900 100644 --- a/tests/shared/src/StorageTests.cpp +++ b/tests/shared/src/StorageTests.cpp @@ -8,6 +8,8 @@ #include "StorageTests.h" +#include + QTEST_MAIN(StorageTests) using namespace storage; @@ -32,8 +34,8 @@ void StorageTests::testConversion() { QFileInfo fileInfo(_testFile); QCOMPARE(fileInfo.exists(), false); } - StoragePointer storagePointer = std::make_unique(_testData.size(), _testData.data()); - QCOMPARE(storagePointer->size(), (quint64)_testData.size()); + StoragePointer storagePointer = std::unique_ptr(new MemoryStorage(_testData.size(), _testData.data())); + QCOMPARE(storagePointer->size(), _testData.size()); QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0); // Convert to a file storagePointer = storagePointer->toFileStorage(_testFile); @@ -42,12 +44,12 @@ void StorageTests::testConversion() { QCOMPARE(fileInfo.exists(), true); QCOMPARE(fileInfo.size(), (qint64)_testData.size()); } - QCOMPARE(storagePointer->size(), (quint64)_testData.size()); + QCOMPARE(storagePointer->size(), _testData.size()); QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0); // Convert to memory storagePointer = storagePointer->toMemoryStorage(); - QCOMPARE(storagePointer->size(), (quint64)_testData.size()); + QCOMPARE(storagePointer->size(), _testData.size()); QCOMPARE(memcmp(_testData.data(), storagePointer->data(), _testData.size()), 0); { // ensure the file is unaffected @@ -58,13 +60,13 @@ void StorageTests::testConversion() { // truncate the data as a new memory object auto newSize = _testData.size() / 2; - storagePointer = std::make_unique(newSize, storagePointer->data()); - QCOMPARE(storagePointer->size(), (quint64)newSize); + storagePointer = std::unique_ptr(new MemoryStorage(newSize, storagePointer->data())); + QCOMPARE(storagePointer->size(), newSize); QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0); // Convert back to file storagePointer = storagePointer->toFileStorage(_testFile); - QCOMPARE(storagePointer->size(), (quint64)newSize); + QCOMPARE(storagePointer->size(), newSize); QCOMPARE(memcmp(_testData.data(), storagePointer->data(), newSize), 0); { // ensure the file is truncated From 81764f0f7165167480804decfe93062dd4d97683 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 09:57:54 -0700 Subject: [PATCH 2/7] fix GLMHelpers::generateBasisVectors() --- libraries/shared/src/GLMHelpers.cpp | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 70237e8ff6..10c73d6c6a 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -49,7 +49,7 @@ const mat4 Matrices::Z_180 { createMatFromQuatAndPos(Quaternions::Z_180, Vectors glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; - + // adjust signs if necessary if (cosa < 0.0f) { cosa = -cosa; @@ -58,19 +58,19 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { oz = -oz; ow = -ow; } - + // calculate coefficients; if the angle is too close to zero, we must fall back // to linear interpolation if ((1.0f - cosa) > EPSILON) { float angle = acosf(cosa), sina = sinf(angle); s0 = sinf((1.0f - proportion) * angle) / sina; s1 = sinf(proportion * angle) / sina; - + } else { s0 = 1.0f - proportion; s1 = proportion; } - + return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); } @@ -105,10 +105,10 @@ int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0f); - + uint16_t angleHolder = floorf((degrees + 180.0f) * ANGLE_CONVERSION_RATIO); memcpy(buffer, &angleHolder, sizeof(uint16_t)); - + return sizeof(uint16_t); } @@ -125,7 +125,7 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput quatParts[1] = floorf((quatNormalized.y + 1.0f) * QUAT_PART_CONVERSION_RATIO); quatParts[2] = floorf((quatNormalized.z + 1.0f) * QUAT_PART_CONVERSION_RATIO); quatParts[3] = floorf((quatNormalized.w + 1.0f) * QUAT_PART_CONVERSION_RATIO); - + memcpy(buffer, &quatParts, sizeof(quatParts)); return sizeof(quatParts); } @@ -133,12 +133,12 @@ int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) { uint16_t quatParts[4]; memcpy(&quatParts, buffer, sizeof(quatParts)); - + quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.0f) - 1.0f; quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.0f) - 1.0f; quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.0f) - 1.0f; quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.0f) - 1.0f; - + return sizeof(quatParts); } @@ -235,7 +235,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) { atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), asinf(sy), atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); - + } else { // not a unique solution; x + z = atan2(-m21, m11) eulers = glm::vec3( @@ -250,7 +250,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) { PI_OVER_TWO, -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } - + // adjust so that z, rather than y, is in [-pi/2, pi/2] if (eulers.z < -PI_OVER_TWO) { if (eulers.x < 0.0f) { @@ -265,7 +265,7 @@ glm::vec3 safeEulerAngles(const glm::quat& q) { eulers.y -= PI; } eulers.z += PI; - + } else if (eulers.z > PI_OVER_TWO) { if (eulers.x < 0.0f) { eulers.x += PI; @@ -320,7 +320,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { for (int i = 0; i < 10; i++) { // store the results of the previous iteration glm::mat3 previous = upper; - + // compute average of the matrix with its inverse transpose float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2]; float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; @@ -334,15 +334,15 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f; upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f; upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f; - + upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f; upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f; upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f; - + upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f; upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f; upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f; - + // compute the difference; if it's small enough, we're done glm::mat3 diff = upper - previous; if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] + @@ -352,7 +352,7 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { } } } - + // now that we have a nice orthogonal matrix, we can extract the rotation quaternion // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]); @@ -473,7 +473,7 @@ glm::mat4 createMatFromScaleQuatAndPos(const glm::vec3& scale, const glm::quat& glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f)); } -// cancel out roll +// cancel out roll glm::quat cancelOutRoll(const glm::quat& q) { glm::vec3 forward = q * Vectors::FRONT; return glm::quat_cast(glm::inverse(glm::lookAt(Vectors::ZERO, forward, Vectors::UP))); @@ -540,15 +540,15 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda // if secondaryAxis is parallel with the primaryAxis, pick another axis. const float EPSILON = 1.0e-4f; - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) { + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) < EPSILON) { // pick a better secondaryAxis. normSecondary = glm::vec3(1.0f, 0.0f, 0.0f); - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) { + if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) < EPSILON) { normSecondary = glm::vec3(0.0f, 1.0f, 0.0f); } } - wAxisOut = glm::normalize(glm::cross(uAxisOut, secondaryAxis)); + wAxisOut = glm::normalize(glm::cross(uAxisOut, normSecondary)); vAxisOut = glm::cross(wAxisOut, uAxisOut); } From 1621d31a8e38b3ea72e8972bd9b27fcea9e5cfee Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 09:58:58 -0700 Subject: [PATCH 3/7] cleanup usage of GLMHelpers::generateBasisVectors() --- libraries/animation/src/Rig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index add3a461af..4a22aa1df1 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1137,7 +1137,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm glm::vec3 headUp = headQuat * Vectors::UNIT_Y; glm::vec3 z, y, x; generateBasisVectors(lookAtVector, headUp, z, y, x); - glm::mat3 m(glm::cross(y, z), y, z); + glm::mat3 m(-x, y, z); glm::quat desiredQuat = glm::normalize(glm::quat_cast(m)); glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat); From 506f522802245d2421c21030b7e1217c384f02a0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 09:59:14 -0700 Subject: [PATCH 4/7] use correct format for float literals --- libraries/render-utils/src/AnimDebugDraw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 162745e76f..4f7f9ef5c4 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -260,7 +260,7 @@ static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPo // there is room, so lets draw a nice bone glm::vec3 uAxis, vAxis, wAxis; - generateBasisVectors(boneAxis0, glm::vec3(1, 0, 0), uAxis, vAxis, wAxis); + generateBasisVectors(boneAxis0, glm::vec3(1.0f, 0.0f, 0.0f), uAxis, vAxis, wAxis); glm::vec3 boneBaseCorners[NUM_BASE_CORNERS]; boneBaseCorners[0] = pose0 * ((uAxis * radius) + (vAxis * radius) + (wAxis * radius)); From 205e5d730927a3852cf914bcedfcc94e3f4549c2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 11:24:36 -0700 Subject: [PATCH 5/7] add unit tests and fix final bugs --- libraries/shared/src/GLMHelpers.cpp | 7 ++- tests/shared/src/GLMHelpersTests.cpp | 74 ++++++++++++++++++++++++++++ tests/shared/src/GLMHelpersTests.h | 1 + 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 10c73d6c6a..7ebaa11da6 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -538,12 +538,11 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda uAxisOut = glm::normalize(primaryAxis); glm::vec3 normSecondary = glm::normalize(secondaryAxis); - // if secondaryAxis is parallel with the primaryAxis, pick another axis. + // if normSecondary is parallel with the primaryAxis, pick another secondary. const float EPSILON = 1.0e-4f; - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) < EPSILON) { - // pick a better secondaryAxis. + if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) { normSecondary = glm::vec3(1.0f, 0.0f, 0.0f); - if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) < EPSILON) { + if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) { normSecondary = glm::vec3(0.0f, 1.0f, 0.0f); } } diff --git a/tests/shared/src/GLMHelpersTests.cpp b/tests/shared/src/GLMHelpersTests.cpp index b4af4729a3..83a294ee1d 100644 --- a/tests/shared/src/GLMHelpersTests.cpp +++ b/tests/shared/src/GLMHelpersTests.cpp @@ -140,3 +140,77 @@ void GLMHelpersTests::testSimd() { } qDebug() << "Done "; } + +void GLMHelpersTests::testGenerateBasisVectors() { + { // very simple case: primary along X, secondary is linear combination of X and Y + glm::vec3 u(1.0f, 0.0f, 0.0f); + glm::vec3 v(1.0f, 1.0f, 0.0f); + glm::vec3 w; + + generateBasisVectors(u, v, u, v, w); + + QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON); + QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON); + } + + { // point primary along Y instead of X + glm::vec3 u(0.0f, 1.0f, 0.0f); + glm::vec3 v(1.0f, 1.0f, 0.0f); + glm::vec3 w; + + generateBasisVectors(u, v, u, v, w); + + QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON); + QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON); + } + + { // pass bad data (both vectors along Y). The helper will guess X for secondary. + glm::vec3 u(0.0f, 1.0f, 0.0f); + glm::vec3 v(0.0f, 1.0f, 0.0f); + glm::vec3 w; + + generateBasisVectors(u, v, u, v, w); + + QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_Y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_X, EPSILON); + QCOMPARE_WITH_ABS_ERROR(w, -Vectors::UNIT_Z, EPSILON); + } + + { // pass bad data (both vectors along X). The helper will guess X for secondary, fail, then guess Y. + glm::vec3 u(1.0f, 0.0f, 0.0f); + glm::vec3 v(1.0f, 0.0f, 0.0f); + glm::vec3 w; + + generateBasisVectors(u, v, u, v, w); + + QCOMPARE_WITH_ABS_ERROR(u, Vectors::UNIT_X, EPSILON); + QCOMPARE_WITH_ABS_ERROR(v, Vectors::UNIT_Y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(w, Vectors::UNIT_Z, EPSILON); + } + + { // general case for arbitrary rotation + float angle = 1.234f; + glm::vec3 axis = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); + glm::quat rotation = glm::angleAxis(angle, axis); + + // expected values + glm::vec3 x = rotation * Vectors::UNIT_X; + glm::vec3 y = rotation * Vectors::UNIT_Y; + glm::vec3 z = rotation * Vectors::UNIT_Z; + + // primary is along x + // secondary is linear combination of x and y + // tertiary is unknown + glm::vec3 u = 1.23f * x; + glm::vec3 v = 2.34f * x + 3.45f * y; + glm::vec3 w; + + generateBasisVectors(u, v, u, v, w); + + QCOMPARE_WITH_ABS_ERROR(u, x, EPSILON); + QCOMPARE_WITH_ABS_ERROR(v, y, EPSILON); + QCOMPARE_WITH_ABS_ERROR(w, z, EPSILON); + } +} diff --git a/tests/shared/src/GLMHelpersTests.h b/tests/shared/src/GLMHelpersTests.h index acc7b533f5..030f2d477f 100644 --- a/tests/shared/src/GLMHelpersTests.h +++ b/tests/shared/src/GLMHelpersTests.h @@ -21,6 +21,7 @@ private slots: void testEulerDecomposition(); void testSixByteOrientationCompression(); void testSimd(); + void testGenerateBasisVectors(); }; float getErrorDifference(const float& a, const float& b); From 6970576bb8e8fd8b6a95cb0aa672f5e1ef2e2982 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 31 May 2017 11:51:35 -0700 Subject: [PATCH 6/7] use helper constants in helper code --- libraries/shared/src/GLMHelpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 7ebaa11da6..394517aac4 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -541,9 +541,9 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda // if normSecondary is parallel with the primaryAxis, pick another secondary. const float EPSILON = 1.0e-4f; if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) { - normSecondary = glm::vec3(1.0f, 0.0f, 0.0f); + normSecondary = Vectors::UNIT_X; if (fabsf(fabsf(glm::dot(uAxisOut, normSecondary)) - 1.0f) < EPSILON) { - normSecondary = glm::vec3(0.0f, 1.0f, 0.0f); + normSecondary = Vectors::UNIT_Y; } } From 793ed1313d7b83c87248d529f38c6da77e1883e5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 5 Jun 2017 10:30:52 -0700 Subject: [PATCH 7/7] change variable name for more readable code --- libraries/animation/src/Rig.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 4a22aa1df1..2d37213c7a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1135,9 +1135,9 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm } glm::vec3 headUp = headQuat * Vectors::UNIT_Y; - glm::vec3 z, y, x; - generateBasisVectors(lookAtVector, headUp, z, y, x); - glm::mat3 m(-x, y, z); + glm::vec3 z, y, zCrossY; + generateBasisVectors(lookAtVector, headUp, z, y, zCrossY); + glm::mat3 m(-zCrossY, y, z); glm::quat desiredQuat = glm::normalize(glm::quat_cast(m)); glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat);