diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2025-06-03 20:27:25 +0300 |
---|---|---|
committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2025-06-04 01:45:27 +0300 |
commit | acd4de66589e960da24cd39fe44083f80a293b05 (patch) | |
tree | 6f64437bcc3e714be3afdde20eb5968c624466f6 /indra | |
parent | b322b3f6f11d6eb9d4113cf1b344d05daf2c1be0 (diff) |
#4080 Rigged mesh support #7
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/gltf/llgltfloader.cpp | 210 | ||||
-rw-r--r-- | indra/newview/gltf/llgltfloader.h | 14 |
2 files changed, 151 insertions, 73 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 4d705279a5..c99d7c2993 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -153,9 +153,9 @@ bool LLGLTFLoader::parseMeshes() // Populate the joints from skins first. // There's not many skins - and you can pretty easily iterate through the nodes from that. - for (auto& skin : mGLTFAsset.mSkins) + for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++) { - populateJointFromSkin(skin); + populateJointFromSkin(i); } // Track how many times each mesh name has been used @@ -293,6 +293,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& base_name = "mesh_" + std::to_string(mesh_index); } + LL_INFOS("GLTF_DEBUG") << "Processing model " << base_name << LL_ENDL; + if (instance_count > 0) { pModel->mLabel = base_name + "_copy_" + std::to_string(instance_count); @@ -672,16 +674,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx]; LLMeshSkinInfo& skin_info = pModel->mSkinInfo; - size_t jointCnt = gltf_skin.mJoints.size(); - if (gltf_skin.mInverseBindMatrices >= 0 && jointCnt != gltf_skin.mInverseBindMatricesData.size()) - { - LL_INFOS("GLTF_IMPORT") << "Bind matrices count mismatch joints count" << LL_ENDL; - LLSD args; - args["Message"] = "InvBindCountMismatch"; - mWarningsArray.append(args); - } - std::vector<S32> gltfindex_to_joitindex_map; + size_t jointCnt = gltf_skin.mJoints.size(); gltfindex_to_joitindex_map.resize(jointCnt); S32 replacement_index = 0; @@ -711,44 +705,24 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& skin_info.mJointNames.push_back(legal_name); skin_info.mJointNums.push_back(-1); - if (i < gltf_skin.mInverseBindMatricesData.size()) - { - // Use pre-computed coord_system_rotation instead of recreating it - LL::GLTF::mat4 gltf_mat = gltf_skin.mInverseBindMatricesData[i]; - - glm::mat4 original_bind_matrix = glm::inverse(gltf_mat); - glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix; - glm::mat4 rotated_inverse_bind_matrix = glm::inverse(rotated_original); - - LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_inverse_bind_matrix)); - skin_info.mInvBindMatrix.push_back(LLMatrix4a(gltf_transform)); - - LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL; + // In scope of same skin multiple meshes reuse same bind matrices + skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[skinIdx][i]); - // For alternate bind matrix, use the ORIGINAL joint transform (before rotation) - // Get the original joint node and use its matrix directly - S32 joint = gltf_skin.mJoints[i]; - LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; - glm::mat4 joint_mat = jointNode.mMatrix; - S32 root_joint = findValidRootJoint(joint, gltf_skin); // skeleton can have multiple real roots - if (root_joint == joint) - { - // This is very likely incomplete in some way. - // Root shouldn't be the only one to need full coordinate fix - joint_mat = coord_system_rotation * joint_mat; - } - LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat)); - - LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << original_joint_transform << LL_ENDL; - skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(original_joint_transform)); - } - else + // For alternate bind matrix, use the ORIGINAL joint transform (before rotation) + // Get the original joint node and use its matrix directly + // Todo: this seems blatantly wrong, it should have been rotated + glm::mat4 joint_mat = jointNode.mMatrix; + S32 root_joint = findValidRootJointNode(joint, gltf_skin); // skeleton can have multiple real roots + if (root_joint == joint) { - // For gltf mInverseBindMatrices are optional, but not for viewer - // todo: get a model that triggers this - skin_info.mInvBindMatrix.push_back(LLMatrix4a(mJointList[legal_name])); // might need to be an 'identity' - skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(mJointList[legal_name])); + // This is very likely incomplete in some way. + // Root shouldn't be the only one to need full coordinate fix + joint_mat = coord_system_rotation * joint_mat; } + LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat)); + + LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << original_joint_transform << LL_ENDL; + skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(original_joint_transform)); } // Remap indices for pModel->mSkinWeights @@ -764,23 +738,71 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& return true; } -void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin) +void LLGLTFLoader::populateJointFromSkin(S32 skin_idx) { - LL_INFOS("GLTF_DEBUG") << "populateJointFromSkin: Processing " << skin.mJoints.size() << " joints" << LL_ENDL; + const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx]; - for (auto joint : skin.mJoints) + LL_INFOS("GLTF_DEBUG") << "populateJointFromSkin: Processing skin " << skin_idx << " with " << skin.mJoints.size() << " joints" << LL_ENDL; + + if (skin.mInverseBindMatrices > 0 && skin.mJoints.size() != skin.mInverseBindMatricesData.size()) { - auto jointNode = mGLTFAsset.mNodes[joint]; + LL_INFOS("GLTF_IMPORT") << "Bind matrices count mismatch joints count" << LL_ENDL; + LLSD args; + args["Message"] = "InvBindCountMismatch"; + mWarningsArray.append(args); + } + S32 joint_count = (S32)skin.mJoints.size(); + S32 inverse_count = (S32)skin.mInverseBindMatricesData.size(); + if (mInverseBindMatrices.size() <= skin_idx) + { + mInverseBindMatrices.resize(skin_idx + 1); + } + + for (S32 i = 0; i < joint_count; i++) + { + S32 joint = skin.mJoints[i]; + LL::GLTF::Node jointNode = mGLTFAsset.mNodes[joint]; std::string legal_name(jointNode.mName); + bool legal_joint = false; if (mJointMap.find(legal_name) != mJointMap.end()) { legal_name = mJointMap[legal_name]; + legal_joint = true; + } + + if (!legal_joint) + { + // add placeholder to not break index + LLMatrix4 gltf_transform; + gltf_transform.setIdentity(); + mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); + } + else if (inverse_count > i) + { + LL::GLTF::mat4 gltf_mat = skin.mInverseBindMatricesData[i]; + + // Todo: there should be a simpler way + glm::mat4 original_bind_matrix = glm::inverse(gltf_mat); + glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix; + glm::mat4 rotated_inverse_bind_matrix = glm::inverse(rotated_original); + LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_inverse_bind_matrix)); + + LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL; + mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); } else { - // ignore unrecognized joint - LL_DEBUGS("GLTF") << "Ignoring joint: " << legal_name << LL_ENDL; + LLMatrix4 gltf_transform; + gltf_transform.setIdentity(); + LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL; + mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); + } + // todo: prepare mAlternateBindMatrix here + + if (!legal_joint) + { + LL_DEBUGS("GLTF") << "Ignoring unrecognized joint: " << legal_name << LL_ENDL; continue; } @@ -812,14 +834,45 @@ void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin) } } -S32 LLGLTFLoader::findValidRootJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const + +S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const { - S32 root_joint = 0; - S32 found_joint = source_joint; + S32 source_joint_node = gltf_skin.mJoints[source_joint]; + S32 root_node = source_joint_node; + S32 found_node = source_joint_node; S32 size = (S32)gltf_skin.mJoints.size(); do { - root_joint = found_joint; + root_node = found_node; + for (S32 i = 0; i < size; i++) + { + S32 joint = gltf_skin.mJoints[i]; + const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; + std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); + if (it != jointNode.mChildren.end()) + { + // Found node's parent + found_node = joint; + if (mJointMap.find(jointNode.mName) != mJointMap.end()) + { + return i; + } + break; + } + } + } while (root_node != found_node); + + return -1; +} + +S32 LLGLTFLoader::findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const +{ + S32 root_node = 0; + S32 found_node = source_joint_node; + S32 size = (S32)gltf_skin.mJoints.size(); + do + { + root_node = found_node; for (S32 i = 0; i < size; i++) { S32 joint = gltf_skin.mJoints[i]; @@ -827,44 +880,61 @@ S32 LLGLTFLoader::findValidRootJoint(S32 source_joint, const LL::GLTF::Skin& glt if (mJointMap.find(jointNode.mName) != mJointMap.end()) { - std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_joint); + std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); if (it != jointNode.mChildren.end()) { - found_joint = joint; + // Found node's parent + found_node = joint; break; } } } - } while (root_joint != found_joint); + } while (root_node != found_node); - return root_joint; + return root_node; } -S32 LLGLTFLoader::findGLTFRootJoint(const LL::GLTF::Skin& gltf_skin) const +S32 LLGLTFLoader::findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const { - S32 root_joint = 0; - S32 found_joint = 0; + S32 root_node = 0; + S32 found_node = 0; S32 size = (S32)gltf_skin.mJoints.size(); do { - root_joint = found_joint; + root_node = found_node; for (S32 i = 0; i < size; i++) { S32 joint = gltf_skin.mJoints[i]; const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; - std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_joint); + std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); if (it != jointNode.mChildren.end()) { - found_joint = joint; + // Found node's parent + found_node = joint; break; } } - } while (root_joint != found_joint); + } while (root_node != found_node); LL_INFOS("GLTF_DEBUG") << "mJointList name: "; - const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[root_joint]; - LL_CONT << jointNode.mName << " index: " << root_joint << LL_ENDL; - return root_joint; + const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[root_node]; + LL_CONT << jointNode.mName << " index: " << root_node << LL_ENDL; + return root_node; +} + +S32 LLGLTFLoader::findParentNode(S32 node) const +{ + S32 size = (S32)mGLTFAsset.mNodes.size(); + for (S32 i = 0; i < size; i++) + { + const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[i]; + std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), node); + if (it != jointNode.mChildren.end()) + { + return i; + } + } + return -1; } bool LLGLTFLoader::parseMaterials() diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h index 6e0fe2b32c..a9572a5bfc 100644 --- a/indra/newview/gltf/llgltfloader.h +++ b/indra/newview/gltf/llgltfloader.h @@ -121,6 +121,7 @@ class LLGLTFLoader : public LLModelLoader { public: typedef std::map<std::string, LLImportMaterial> material_map; + typedef std::map<std::string, LLVector3> joint_pos_map_t; LLGLTFLoader(std::string filename, S32 lod, @@ -162,6 +163,11 @@ protected: std::vector<gltf_image> mImages; std::vector<gltf_sampler> mSamplers; + + // vector of vectors because of a posibility of having more than one skin + typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t; + bind_matrices_t mInverseBindMatrices; + private: bool parseMeshes(); void uploadMeshes(); @@ -169,9 +175,11 @@ private: void uploadMaterials(); void computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const; bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats, S32 instance_count); - void populateJointFromSkin(const LL::GLTF::Skin& skin); - S32 findValidRootJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const; - S32 findGLTFRootJoint(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint + void populateJointFromSkin(S32 skin_idx); + S32 findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const; + S32 findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const; + S32 findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint + S32 findParentNode(S32 node) const; LLUUID imageBufferToTextureUUID(const gltf_texture& tex); void notifyUnsupportedExtension(bool unsupported); |