From 991ba7f1951db5043dd8fbf73ba6403b193f38eb Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 23 Jan 2018 16:05:43 -0800 Subject: [PATCH] Bug fix for twisted knees on some avatars. The FBXReader inverse bind pose calculation can sometimes introduce floating point fuzz into the bottom row of the matrix. The Transform class checks this bottom row before doing decomposition into translation, rotation and scale. If it detects that this row is not exactly (0, 0, 0, 1) it aborts. And returns identity. To guarantee that it preforms the decomposition correctly slam the row to (0, 0, 0, 1), before conversion to a Transform instance. --- libraries/fbx/src/FBXReader.cpp | 14 ++++++++++++-- libraries/render-utils/src/Skinning.slh | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 4bc5eb1b6d..171fc88443 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1733,8 +1733,18 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS qCDebug(modelformat) << "Joint not in model list: " << jointID; fbxCluster.jointIndex = 0; } + fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform; + + // slam bottom row to (0, 0, 0, 1), we KNOW this is not a perspective matrix and + // sometimes floating point fuzz can be introduced after the inverse. + fbxCluster.inverseBindMatrix[0][3] = 0.0f; + fbxCluster.inverseBindMatrix[1][3] = 0.0f; + fbxCluster.inverseBindMatrix[2][3] = 0.0f; + fbxCluster.inverseBindMatrix[3][3] = 1.0f; + fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix); + extracted.mesh.clusters.append(fbxCluster); // override the bind rotation with the transform link @@ -1836,13 +1846,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } // now that we've accumulated the most relevant weights for each vertex - // normalize and compress to 8-bits + // normalize and compress to 16-bits extracted.mesh.clusterWeights.fill(0, numClusterIndices); int numVertices = extracted.mesh.vertices.size(); for (int i = 0; i < numVertices; ++i) { int j = i * WEIGHTS_PER_VERTEX; - // normalize weights into uint8_t + // normalize weights into uint16_t float totalWeight = weightAccumulators[j]; for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) { totalWeight += weightAccumulators[k]; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 49d0df3d2c..e85ee75c58 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -39,12 +39,12 @@ mat4 dualQuatToMat4(vec4 real, vec4 dual) { twoRealXZ - twoRealYW, 0.0); vec4 col1 = vec4(twoRealXY - twoRealZW, - 1 - twoRealXSq - twoRealZSq, + 1.0 - twoRealXSq - twoRealZSq, twoRealYZ + twoRealXW, 0.0); vec4 col2 = vec4(twoRealXZ + twoRealYW, twoRealYZ - twoRealXW, - 1 - twoRealXSq - twoRealYSq, + 1.0 - twoRealXSq - twoRealYSq, 0.0); vec4 col3 = vec4(2.0 * (-dual.w * real.x + dual.x * real.w - dual.y * real.z + dual.z * real.y), 2.0 * (-dual.w * real.y + dual.x * real.z + dual.y * real.w - dual.z * real.x),