diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index fc6334e649..4fca486b56 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -87,6 +87,25 @@ static const glm::mat4 coord_system_rotationxy( 0.f, 0.f, 0.f, 1.f ); +// Use a full basis change for transform matrices. Pre-multiplying is +// correct for point positions but not for joint rest/bind matrices. +static glm::mat4 build_viewer_basis_transform(bool apply_xy_rotation) +{ + glm::mat4 basis = coord_system_rotation; + if (apply_xy_rotation) + { + basis = coord_system_rotationxy * basis; + } + return basis; +} + +static glm::mat4 convert_transform_to_viewer_basis(const glm::mat4& transform, bool apply_xy_rotation) +{ + const glm::mat4 basis = build_viewer_basis_transform(apply_xy_rotation); + return basis * transform * glm::inverse(basis); +} +// + static const S32 VERTEX_SPLIT_SAFETY_MARGIN = 3 * 3 + 1; // 10 vertices: 3 complete triangles plus remapping overhead static const S32 VERTEX_LIMIT = USHRT_MAX - VERTEX_SPLIT_SAFETY_MARGIN; @@ -1372,7 +1391,12 @@ void LLGLTFLoader::populateJointsFromSkin(S32 skin_idx) { // Transalte existing bind matrix to viewer's overriden skeleton glm::mat4 original_bind_matrix = glm::inverse(skin.mInverseBindMatricesData[i]); - glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix; + // Transform matrices need a basis change, not a simple + // left multiply, otherwise non-T-pose rigs can pick up a 90 degree + // axis error in the converted bind state. + // glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix; + glm::mat4 rotated_original = convert_transform_to_viewer_basis(original_bind_matrix, mApplyXYRotation); + // glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(joints_data, joint, legal_name); glm::mat4 tranlated_original = skeleton_transform * rotated_original; glm::mat4 final_inverse_bind_matrix = glm::inverse(tranlated_original); @@ -1463,11 +1487,15 @@ void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map node.mIsOverrideValid = true; node.mViewerRestMatrix = viewer_data.mRestMatrix; - glm::mat4 gltf_joint_rest_pose = coord_system_rotation * node.mGltfRestMatrix; - if (mApplyXYRotation) - { - gltf_joint_rest_pose = coord_system_rotationxy * gltf_joint_rest_pose; - } + // Convert joint rest matrices with a full basis change so the + // bind/rest chain stays in a consistent viewer-space frame. + // glm::mat4 gltf_joint_rest_pose = coord_system_rotation * node.mGltfRestMatrix; + // if (mApplyXYRotation) + // { + // gltf_joint_rest_pose = coord_system_rotationxy * gltf_joint_rest_pose; + // } + glm::mat4 gltf_joint_rest_pose = convert_transform_to_viewer_basis(node.mGltfRestMatrix, mApplyXYRotation); + // glm::mat4 translated_joint; // Example: @@ -1495,14 +1523,20 @@ void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map // fortunately normal bones use only translation, without rotation or scale node.mOverrideMatrix = glm::recompose(glm::vec3(1, 1, 1), glm::identity(), translation_override, glm::vec3(0, 0, 0), glm::vec4(0, 0, 0, 1)); - glm::mat4 overriden_joint = node.mOverrideMatrix; - - // todo: if gltf bone had rotation or scale, they probably should be saved here - // then applied to bind matrix - rest = parent_rest * overriden_joint; + // Keep the full local TRS for bind/rest propagation. + // glm::mat4 overriden_joint = node.mOverrideMatrix; + // // todo: if gltf bone had rotation or scale, they probably should be saved here + // // then applied to bind matrix + // rest = parent_rest * overriden_joint; + // if (viewer_data.mIsJoint) { + // Keep the full local TRS for bind/rest propagation. + // Using the translation-only override here re-encodes parent + // rotation into child translations and causes the sawtooth arm bug. + rest = parent_rest * translated_joint; node.mOverrideRestMatrix = rest; + // } else { @@ -1512,8 +1546,13 @@ void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map // then subsctruct them from bind matrix // Todo: get models that use collision bones, made by different programs - overriden_joint = glm::scale(overriden_joint, viewer_data.mScale); - node.mOverrideRestMatrix = parent_support_rest * overriden_joint; + // Match the standard-joint path and preserve the full local + // transform in the propagated rest state. + // overriden_joint = glm::scale(overriden_joint, viewer_data.mScale); + // node.mOverrideRestMatrix = parent_support_rest * overriden_joint; + rest = parent_support_rest * translated_joint; + node.mOverrideRestMatrix = rest; + // } } else @@ -1559,7 +1598,13 @@ glm::mat4 LLGLTFLoader::buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF if (it != potential_parent.mChildren.end()) { // Found parent - if (std::find(gltf_skin.mJoints.begin(), gltf_skin.mJoints.end(), joint_node_index) != gltf_skin.mJoints.end()) + // Recurse only while the parent is also part of the skin + // joint set. The previous test accidentally checked the child node + // again and folded non-joint parents into the reconstructed rest + // chain. + // if (std::find(gltf_skin.mJoints.begin(), gltf_skin.mJoints.end(), joint_node_index) != gltf_skin.mJoints.end()) + if (std::find(gltf_skin.mJoints.begin(), gltf_skin.mJoints.end(), static_cast(i)) != gltf_skin.mJoints.end()) + // { // parent is a joint - recursively combine transform // assumes that matrix is already valid @@ -1604,8 +1649,12 @@ glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const joints_data_m } // Get the GLTF joint's rest pose (in GLTF coordinate system) - const glm::mat4 &gltf_joint_rest_pose = node_data.mGltfRestMatrix; - glm::mat4 rest_pose = coord_system_rotation * gltf_joint_rest_pose; + // Keep the rest-pose conversion consistent with the bind/rest + // construction used above. + // const glm::mat4 &gltf_joint_rest_pose = node_data.mGltfRestMatrix; + // glm::mat4 rest_pose = coord_system_rotation * gltf_joint_rest_pose; + glm::mat4 rest_pose = convert_transform_to_viewer_basis(node_data.mGltfRestMatrix, mApplyXYRotation); + // LL_INFOS("GLTF_DEBUG") << "rest matrix for joint " << joint_name << ": ";