diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 3ffacb8836..86deff095b 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -112,9 +112,9 @@ void CauterizedModel::updateClusterMatrices() { auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); #if defined(SKIN_DQ) + // AJT: TODO: optimize glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); @@ -145,9 +145,9 @@ void CauterizedModel::updateClusterMatrices() { } #if defined(SKIN_DQ) + // AJT: TODO: optimize glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); - AnimPose p(m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); #else glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); @@ -220,7 +220,10 @@ void CauterizedModel::updateRenderItems() { Transform renderTransform = modelTransform; if (clusterTransforms.size() == 1) { #if defined(SKIN_DQ) - renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0].getMatrix())); + Transform transform(clusterTransforms[0].getRotation(), + clusterTransforms[0].getScale(), + clusterTransforms[0].getTranslation()); + renderTransform = modelTransform.worldTransform(transform); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0])); #endif @@ -230,7 +233,10 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform; if (clusterTransformsCauterized.size() == 1) { #if defined(SKIN_DQ) - renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0].getMatrix())); + Transform transform(clusterTransforms[0].getRotation(), + clusterTransforms[0].getScale(), + clusterTransforms[0].getTranslation()); + renderTransform = modelTransform.worldTransform(Transform(transform)); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); #endif diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 481d4574ab..e3bbfc1c03 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -332,7 +332,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in Transform renderTransform = transform; if (state.clusterTransforms.size() == 1) { #if defined(SKIN_DQ) - renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0].getMatrix())); + Transform transform(state.clusterTransforms[0].getRotation(), + state.clusterTransforms[0].getScale(), + state.clusterTransforms[0].getTranslation()); + renderTransform = transform.worldTransform(Transform(transform)); #else renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0])); #endif @@ -549,7 +552,10 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector 0) { #if defined(SKIN_DQ) - _adjustedLocalBound.transform(clusterTransforms[0].getMatrix()); + Transform rootTransform(clusterTransforms[0].getRotation(), + clusterTransforms[0].getScale(), + clusterTransforms[0].getTranslation()); + _adjustedLocalBound.transform(rootTransform); #else _adjustedLocalBound.transform(clusterTransforms[0]); #endif @@ -557,7 +563,10 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector <@def SKINNING_SLH@> +// Use dual quaternion skinning +// Must match #define SKIN_DQ in Model.h +<@def SKIN_DQ@> + const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; @@ -18,33 +22,46 @@ layout(std140) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; -vec4 quatConj(vec4 v) { - return vec4(-v.x, -v.y, -v.z, v.w); -} - -vec4 quatMul(vec4 q1, vec4 q2) { - return vec4( q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x, - -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y, - q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z, - -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w); -} - -vec3 rotateByQuat(vec4 q, vec3 p) { - return vec3(quatMul(quatMul(q, vec4(p.x, p.y, p.z, 0.0)), quatConj(q))); -} - -void dqMul(vec4 lhsReal, vec4 lhsImag, vec4 rhsReal, vec4 rhsImag, out vec4 realOut, out vec4 imagOut) { - realOut = quatMul(lhsReal, rhsReal); - imagOut = quatMul(lhsReal, rhsImag) + quatMul(lhsImag, rhsReal); +<@if SKIN_DQ@> + +mat4 dualQuatToMat4(vec4 real, vec4 imag) { + float twoRealXSq = 2.0 * real.x * real.x; + float twoRealYSq = 2.0 * real.y * real.y; + float twoRealZSq = 2.0 * real.z * real.z; + float twoRealXY = 2.0 * real.x * real.y; + float twoRealXZ = 2.0 * real.x * real.z; + float twoRealXW = 2.0 * real.x * real.w; + float twoRealZW = 2.0 * real.z * real.w; + float twoRealYZ = 2.0 * real.y * real.z; + float twoRealYW = 2.0 * real.y * real.w; + vec4 col0 = vec4(1.0 - twoRealYSq - twoRealZSq, + twoRealXY + twoRealZW, + twoRealXZ - twoRealYW, + 0.0); + vec4 col1 = vec4(twoRealXY - twoRealZW, + 1 - twoRealXSq - twoRealZSq, + twoRealYZ + twoRealXW, + 0.0); + vec4 col2 = vec4(twoRealXZ + twoRealYW, + twoRealYZ - twoRealXW, + 1 - twoRealXSq - twoRealYSq, + 0.0); + vec4 col3 = vec4(2.0 * (-imag.w * real.x + imag.x * real.w - imag.y * real.z + imag.z * real.y), + 2.0 * (-imag.w * real.y + imag.x * real.z + imag.y * real.w - imag.z * real.x), + 2.0 * (-imag.w * real.z - imag.x * real.y + imag.y * real.x + imag.z * real.w), + 1.0); + + return mat4(col0, col1, col2, col3); } +// dual quaternion linear blending void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { + // linearly blend scale and dual quaternion components 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 polarityReference = clusterMatrices[skinClusterIndex[0]][1]; - for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; @@ -64,46 +81,20 @@ void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPositio iAccum += imag * dqClusterWeight; } + // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; iAccum /= norm; - float xe = iAccum.x; - float ye = iAccum.y; - float ze = iAccum.z; - float we = iAccum.w; - - float x0 = rAccum.x; - float y0 = rAccum.y; - float z0 = rAccum.z; - float w0 = rAccum.w; - - float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0); - float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0); - float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0); - - vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0, - 2.0 * x0 * y0 + 2.0 * w0 * z0, - 2.0 * x0 * z0 - 2.0 * w0 * y0, - 0.0); - vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0, - 1 - 2.0 * x0 * x0 - 2.0 * z0 * z0, - 2.0 * y0 * z0 + 2.0 * w0 * x0, - 0.0); - vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0, - 2.0 * y0 * z0 - 2.0 * w0 * x0, - 1 - 2.0 * x0 * x0 - 2.0 * y0 * y0, - 0.0); - vec4 col3 = vec4(t0, t1, t2, 1.0); - - mat4 m = mat4(col0, col1, col2, col3); - + // conversion from dual quaternion to 4x4 matrix. + mat4 m = dualQuatToMat4(rAccum, iAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); } void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { + // linearly blend scale and dual quaternion components 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); @@ -128,40 +119,13 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP iAccum += imag * dqClusterWeight; } + // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; iAccum /= norm; - float xe = iAccum.x; - float ye = iAccum.y; - float ze = iAccum.z; - float we = iAccum.w; - - float x0 = rAccum.x; - float y0 = rAccum.y; - float z0 = rAccum.z; - float w0 = rAccum.w; - - float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0); - float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0); - float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0); - - vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0, - 2.0 * x0 * y0 + 2.0 * w0 * z0, - 2.0 * x0 * z0 - 2.0 * w0 * y0, - 0.0); - vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0, - 1 - 2.0 * x0 * x0 - 2.0 * z0 * z0, - 2.0 * y0 * z0 + 2.0 * w0 * x0, - 0.0); - vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0, - 2.0 * y0 * z0 - 2.0 * w0 * x0, - 1 - 2.0 * x0 * x0 - 2.0 * y0 * y0, - 0.0); - vec4 col3 = vec4(t0, t1, t2, 1.0); - - mat4 m = mat4(col0, col1, col2, col3); - + // conversion from dual quaternion to 4x4 matrix. + mat4 m = dualQuatToMat4(rAccum, iAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); skinnedNormal = vec3(m * vec4(inNormal, 0)); } @@ -169,6 +133,7 @@ void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inP void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { + // linearly blend scale and dual quaternion components 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); @@ -193,134 +158,67 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v iAccum += imag * dqClusterWeight; } + // normalize dual quaternion float norm = length(rAccum); rAccum /= norm; iAccum /= norm; - float xe = iAccum.x; - float ye = iAccum.y; - float ze = iAccum.z; - float we = iAccum.w; - - float x0 = rAccum.x; - float y0 = rAccum.y; - float z0 = rAccum.z; - float w0 = rAccum.w; - - float t0 = 2.0 * (-we * x0 + xe * w0 - ye * z0 + ze * y0); - float t1 = 2.0 * (-we * y0 + xe * z0 + ye * w0 - ze * x0); - float t2 = 2.0 * (-we * z0 - xe * y0 + ye * x0 + ze * w0); - - vec4 col0 = vec4(1.0 - 2.0 * y0 * y0 - 2.0 * z0 * z0, - 2.0 * x0 * y0 + 2.0 * w0 * z0, - 2.0 * x0 * z0 - 2.0 * w0 * y0, - 0.0); - vec4 col1 = vec4(2.0 * x0 * y0 - 2.0 * w0 * z0, - 1 - 2.0 * x0 * x0 - 2.0 * z0 * z0, - 2.0 * y0 * z0 + 2.0 * w0 * x0, - 0.0); - vec4 col2 = vec4(2.0 * x0 * z0 + 2.0 * w0 * y0, - 2.0 * y0 * z0 - 2.0 * w0 * x0, - 1 - 2.0 * x0 * x0 - 2.0 * y0 * y0, - 0.0); - vec4 col3 = vec4(t0, t1, t2, 1.0); - - mat4 m = mat4(col0, col1, col2, col3); - + // conversion from dual quaternion to 4x4 matrix. + mat4 m = dualQuatToMat4(rAccum, iAccum); skinnedPosition = m * (vec4(sAccum, 1) * inPosition); skinnedNormal = vec3(m * vec4(inNormal, 0)); skinnedTangent = vec3(m * vec4(inTangent, 0)); } -// SKIN_COMP -/* +<@else@> // SKIN_DQ + void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { - vec3 sAccum = vec3(0.0, 0.0, 0.0); - vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); - vec3 tAccum = vec3(0.0, 0.0, 0.0); + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; - - vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]); - - if (dot(r, rAccum) < 0) { - r = -r; - } - - sAccum += s * clusterWeight; - rAccum += r * clusterWeight; - tAccum += t * clusterWeight; + newPosition += clusterMatrix * inPosition * clusterWeight; } - rAccum = normalize(rAccum); - - skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); + skinnedPosition = newPosition; } void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { - - vec3 sAccum = vec3(0.0, 0.0, 0.0); - vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); - vec3 tAccum = vec3(0.0, 0.0, 0.0); + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; - - vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]); - - if (dot(r, rAccum) < 0) { - r = -r; - } - - sAccum += s * clusterWeight; - rAccum += r * clusterWeight; - tAccum += t * clusterWeight; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; } - rAccum = normalize(rAccum); - - skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); - skinnedNormal = rotateByQuat(rAccum, inNormal); + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; } void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { - - vec3 sAccum = vec3(0.0, 0.0, 0.0); - vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0); - vec3 tAccum = vec3(0.0, 0.0, 0.0); + vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); + vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; - - vec3 s = vec3(clusterMatrix[0][0], clusterMatrix[0][1], clusterMatrix[0][2]); - vec4 r = vec4(clusterMatrix[1][0], clusterMatrix[1][1], clusterMatrix[1][2], clusterMatrix[1][3]); - vec3 t = vec3(clusterMatrix[2][0], clusterMatrix[2][1], clusterMatrix[2][2]); - - if (dot(r, rAccum) < 0) { - r = -r; - } - - sAccum += s * clusterWeight; - rAccum += r * clusterWeight; - tAccum += t * clusterWeight; + newPosition += clusterMatrix * inPosition * clusterWeight; + newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; + newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight; } - rAccum = normalize(rAccum); - - skinnedPosition = vec4(rotateByQuat(rAccum, (vec3(inPosition) * sAccum)) + tAccum, 1); - skinnedNormal = rotateByQuat(rAccum, inNormal); - skinnedTangent = rotateByQuat(rAccum, inTangent); + skinnedPosition = newPosition; + skinnedNormal = newNormal.xyz; + skinnedTangent = newTangent.xyz; } -*/ -<@endif@> +<@endif@> // if SKIN_DQ + +<@endif@> // if not SKINNING_SLH diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 58b5eea222..fe74dc3c87 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -52,17 +52,26 @@ void SoftAttachmentModel::updateClusterMatrices() { // TODO: cache these look-ups as an optimization int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); +#if defined(SKIN_DQ) glm::mat4 jointMatrix; if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { jointMatrix = _rigOverride.getJointTransform(jointIndexOverride); } else { jointMatrix = _rig.getJointTransform(cluster.jointIndex); } -#if defined(SKIN_DQ) + + // AJT: TODO: OPTIMIZE glm::mat4 m; glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m); state.clusterTransforms[j] = Model::TransformDualQuaternion(m); #else + glm::mat4 jointMatrix; + if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { + jointMatrix = _rigOverride.getJointTransform(jointIndexOverride); + } else { + jointMatrix = _rig.getJointTransform(cluster.jointIndex); + } + glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]); #endif } diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 7a39314f4d..90bfc1aaa6 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -58,7 +58,7 @@ public: _rotation(rotation), _scale(scale), _translation(translation), - _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache + _flags(0xf) // FLAG_TRANSLATION | FLAG_ROTATION | FLAG_SCALING | FLAG_NON_UNIFORM { if (!isValidScale(_scale)) { _scale = Vec3(1.0f);