From 5bb0b06061a97633f052e5368b2c218b2f0c342f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 21 Dec 2017 18:15:30 -0800 Subject: [PATCH] WIP: Dual Quaternion compensation for spinning the right way. --- .../render-utils/src/CauterizedModel.cpp | 51 ++++++++++++++++++- libraries/render-utils/src/Model.h | 2 +- libraries/render-utils/src/Skinning.slh | 42 ++++++++++++--- libraries/shared/src/DualQuaternion.cpp | 17 +++++-- libraries/shared/src/DualQuaternion.h | 3 ++ 5 files changed, 104 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index cf6aebc952..5be93304ab 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -113,7 +113,12 @@ void CauterizedModel::updateClusterMatrices() { for (int i = 0; i < (int)_meshStates.size(); i++) { Model::MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); +#if defined(SKIN_DQ) + // HACK: FOR DQ go thru reverse order! + for (int j = mesh.clusters.size() - 1; j >= 0; j--) { +#else for (int j = 0; j < mesh.clusters.size(); j++) { +#endif const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -127,6 +132,25 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + + // AJT: HACK n^2!!!! fix me, find parent clusterTransform. + int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); + int parentClusterIndex = -1; + // scan for parent! + for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { + if (mesh.clusters[ii].jointIndex == parentIndex) { + parentClusterIndex = ii; + break; + } + } + + // ensure that we have the same polarity as our parent! + if (parentClusterIndex >= 0) { + //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { + if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { + state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; + } + } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif @@ -146,7 +170,13 @@ void CauterizedModel::updateClusterMatrices() { for (int i = 0; i < _cauterizeMeshStates.size(); i++) { Model::MeshState& state = _cauterizeMeshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); - for (int j = 0; j < mesh.clusters.size(); j++) { + +#if defined(SKIN_DQ) + // HACK: FOR DQ go thru reverse order! + for (int j = mesh.clusters.size() - 1; j >= 0; j--) { +#else + for (int j = 0; j < mesh.clusters.size(); j++) { +#endif const FBXCluster& cluster = mesh.clusters.at(j); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); @@ -164,6 +194,25 @@ void CauterizedModel::updateClusterMatrices() { glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); + + // AJT: HACK n^2!!!! fix me, find parent clusterTransform. + int parentIndex = _rig.getJointParentIndex(cluster.jointIndex); + int parentClusterIndex = -1; + // scan for parent! + for (int ii = mesh.clusters.size() - 1; ii > j; ii--) { + if (mesh.clusters[ii].jointIndex == parentIndex) { + parentClusterIndex = ii; + break; + } + } + + // ensure that we have the same polarity as our parent! + if (parentClusterIndex >= 0) { + //if (state.clusterTransforms[parentClusterIndex]._dq.dot(state.clusterTransforms[j]._dq) < 0.0f) { + if (glm::dot(state.clusterTransforms[parentClusterIndex]._dq.real(), state.clusterTransforms[j]._dq.real()) < 0.0f) { + state.clusterTransforms[j]._dq = -state.clusterTransforms[j]._dq; + } + } #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f869634dd2..cb211a1011 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -313,7 +313,7 @@ public: glm::quat getRot() const { return _dq.getRotation(); } glm::vec3 getTrans() const { return _dq.getTranslation(); } glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRot(), getTrans()); }; - protected: + public: // AJT: TODO FIX ME. glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f }; DualQuaternion _dq; glm::vec4 _padding; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 17c3a26079..bdba724d43 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -43,6 +43,7 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio vec3 sAccum = vec3(0.0, 0.0, 0.0); vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -52,9 +53,18 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); @@ -100,6 +110,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP vec3 sAccum = vec3(0.0, 0.0, 0.0); vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -109,9 +120,18 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); @@ -158,6 +178,7 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v vec3 sAccum = vec3(0.0, 0.0, 0.0); vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); vec4 iAccum = vec4(0.0, 0.0, 0.0, 0.0); + vec4 prevR = vec4(0.0, 0.0, 0.0, 1.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; @@ -167,9 +188,18 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v vec4 real = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); vec4 imag = vec4(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2], clusterMatrix[2][3]); + float dqClusterWeight = clusterWeight; + if (i == 0) { + prevR = real; + } else { + if (dot(prevR, real) < 0) { + dqClusterWeight = -clusterWeight; + } + } + sAccum += scale * clusterWeight; - rAccum += real * clusterWeight; - iAccum += imag * clusterWeight; + rAccum += real * dqClusterWeight; + iAccum += imag * dqClusterWeight; } float norm = length(rAccum); diff --git a/libraries/shared/src/DualQuaternion.cpp b/libraries/shared/src/DualQuaternion.cpp index e9b1a65635..44d7356463 100644 --- a/libraries/shared/src/DualQuaternion.cpp +++ b/libraries/shared/src/DualQuaternion.cpp @@ -59,26 +59,37 @@ glm::vec3 DualQuaternion::getTranslation() const { return glm::vec3(result.x, result.y, result.z); } - glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const { return _real * rhs; } +// AJT: UNTESTED DualQuaternion DualQuaternion::inverse() const { glm::quat invReal = glm::inverse(_real); return DualQuaternion(invReal, - invReal * _imag * invReal); } +// AJT: UNTESTED DualQuaternion DualQuaternion::conjugate() const { return DualQuaternion(glm::conjugate(_real), glm::conjugate(_imag)); } +// AJT: UNTESTED float DualQuaternion::length() const { - DualQuaternion result = *this * conjugate(); - return sqrtf(result._real.w); + float dot = this->dot(*this); + return sqrtf(dot); } DualQuaternion DualQuaternion::normalize() const { float invLen = 1.0f / length(); return *this * invLen; } + +float DualQuaternion::dot(const DualQuaternion& rhs) const { + DualQuaternion result = *this * conjugate(); + return result._real.w; +} + +DualQuaternion DualQuaternion::operator-() const { + return DualQuaternion(-_real, -_imag); +} diff --git a/libraries/shared/src/DualQuaternion.h b/libraries/shared/src/DualQuaternion.h index 061317bde9..508570a930 100644 --- a/libraries/shared/src/DualQuaternion.h +++ b/libraries/shared/src/DualQuaternion.h @@ -44,6 +44,8 @@ public: DualQuaternion conjugate() const; float length() const; DualQuaternion normalize() const; + float dot(const DualQuaternion& rhs) const; + DualQuaternion operator-() const; protected: friend QDebug operator<<(QDebug debug, const DualQuaternion& pose); @@ -51,6 +53,7 @@ protected: glm::quat _imag; }; + inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) { debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), imag = (" << dq._imag.x << dq._imag.y << dq._imag.z << dq._imag.w << ")"; return debug;