diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2025-06-04 18:00:14 +0300 |
---|---|---|
committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2025-06-05 01:14:50 +0300 |
commit | 11ece6840b034973a33626e98bd2412f0577ac5a (patch) | |
tree | b2d7434c914ce1aa12b4fa50d838b98da29ebc58 | |
parent | acd4de66589e960da24cd39fe44083f80a293b05 (diff) |
#4214 Support mesh splitting for meshes with more than 8 materials
-rw-r--r-- | indra/newview/gltf/llgltfloader.cpp | 107 | ||||
-rw-r--r-- | indra/newview/gltf/llgltfloader.h | 6 |
2 files changed, 105 insertions, 8 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index c99d7c2993..e330c1d611 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -102,7 +102,8 @@ LLGLTFLoader::LLGLTFLoader(std::string filename, maxJointsPerMesh ), //mPreprocessGLTF(preprocess), mMeshesLoaded(false), - mMaterialsLoaded(false) + mMaterialsLoaded(false), + mGeneratedModelLimit(modelLimit) { } @@ -135,6 +136,99 @@ bool LLGLTFLoader::OpenFile(const std::string &filename) return (mMeshesLoaded); } +void LLGLTFLoader::addModelToScene( + LLModel* pModel, + U32 submodel_limit, + const LLMatrix4& transformation, + const LLVolumeParams& volume_params) +{ + U32 volume_faces = pModel->getNumVolumeFaces(); + + // Side-steps all manner of issues when splitting models + // and matching lower LOD materials to base models + // + pModel->sortVolumeFacesByMaterialName(); + + int submodelID = 0; + + // remove all faces that definitely won't fit into one model and submodel limit + U32 face_limit = (submodel_limit + 1) * LL_SCULPT_MESH_MAX_FACES; + if (face_limit < volume_faces) + { + pModel->setNumVolumeFaces(face_limit); + } + + LLVolume::face_list_t remainder; + std::vector<LLModel*> ready_models; + LLModel* current_model = pModel; + do + { + current_model->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder); + + // remove unused/redundant vertices after normalizing + current_model->remapVolumeFaces(); + + volume_faces = static_cast<U32>(remainder.size()); + + // Don't add to scene yet because weights and materials aren't ready. + // Just save it + ready_models.push_back(current_model); + + // If we have left-over volume faces, create another model + // to absorb them. + if (volume_faces) + { + LLModel* next = new LLModel(volume_params, 0.f); + next->ClearFacesAndMaterials(); + next->mSubmodelID = ++submodelID; + next->mLabel = pModel->mLabel + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod]; + next->getVolumeFaces() = remainder; + next->mNormalizedScale = current_model->mNormalizedScale; + next->mNormalizedTranslation = current_model->mNormalizedTranslation; + next->mSkinWeights = current_model->mSkinWeights; + next->mPosition = current_model->mPosition; + + const LLMeshSkinInfo& current_skin_info = current_model->mSkinInfo; + LLMeshSkinInfo& next_skin_info = next->mSkinInfo; + next_skin_info.mJointNames = current_skin_info.mJointNames; + next_skin_info.mJointNums = current_skin_info.mJointNums; + next_skin_info.mBindShapeMatrix = current_skin_info.mBindShapeMatrix; + next_skin_info.mInvBindMatrix = current_skin_info.mInvBindMatrix; + next_skin_info.mAlternateBindMatrix = current_skin_info.mAlternateBindMatrix; + next_skin_info.mPelvisOffset = current_skin_info.mPelvisOffset; + + + if (current_model->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES) + { + next->mMaterialList.assign(current_model->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, current_model->mMaterialList.end()); + current_model->mMaterialList.resize(LL_SCULPT_MESH_MAX_FACES); + } + + current_model = next; + } + + remainder.clear(); + + } while (volume_faces); + + for (auto model : ready_models) + { + // remove unused/redundant vertices + current_model->remapVolumeFaces(); + // Todo: go over skin weights, joints, matrices and remove unused ones + + mModelList.push_back(model); + + std::map<std::string, LLImportMaterial> materials; + for (U32 i = 0; i < (U32)model->mMaterialList.size(); ++i) + { + materials[model->mMaterialList[i]] = LLImportMaterial(); + } + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); + stretch_extents(model, transformation); + } +} + bool LLGLTFLoader::parseMeshes() { if (!mGltfLoaded) return false; @@ -160,6 +254,7 @@ bool LLGLTFLoader::parseMeshes() // Track how many times each mesh name has been used std::map<std::string, S32> mesh_name_counts; + U32 submodel_limit = mGLTFAsset.mNodes.size() > 0 ? mGeneratedModelLimit / (U32)mGLTFAsset.mNodes.size() : 0; // Process each node for (auto& node : mGLTFAsset.mNodes) @@ -188,8 +283,6 @@ bool LLGLTFLoader::parseMeshes() (LLModel::NO_ERRORS == pModel->getStatus()) && validate_model(pModel)) { - mModelList.push_back(pModel); - mTransform.setIdentity(); transformation = mTransform; @@ -234,8 +327,7 @@ bool LLGLTFLoader::parseMeshes() mWarningsArray.append(args); } - mScene[transformation].push_back(LLModelInstance(pModel, pModel->mLabel, transformation, mats)); - stretch_extents(pModel, transformation); + addModelToScene(pModel, submodel_limit, transformation, volume_params); } else { @@ -347,8 +439,7 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& } } - auto prims = mesh.mPrimitives; - for (auto prim : prims) + for (const LL::GLTF::Primitive& prim : mesh.mPrimitives) { // Unfortunately, SLM does not support 32 bit indices. Filter out anything that goes beyond 16 bit. if (prim.getVertexCount() < USHRT_MAX) @@ -471,7 +562,7 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& { vert.weights = glm::vec4(prim.mWeights[i]); - auto accessorIdx = prim.mAttributes["JOINTS_0"]; + auto accessorIdx = prim.mAttributes.at("JOINTS_0"); LL::GLTF::Accessor::ComponentType componentType = LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE; if (accessorIdx >= 0) { diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h index a9572a5bfc..a3ee8d91df 100644 --- a/indra/newview/gltf/llgltfloader.h +++ b/indra/newview/gltf/llgltfloader.h @@ -155,6 +155,7 @@ protected: bool mGltfLoaded; bool mMeshesLoaded; bool mMaterialsLoaded; + U32 mGeneratedModelLimit; std::vector<gltf_mesh> mMeshes; std::vector<gltf_render_material> mMaterials; @@ -176,6 +177,11 @@ private: 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(S32 skin_idx); + void addModelToScene( + LLModel* pModel, + U32 submodel_limit, + const LLMatrix4& transformation, + const LLVolumeParams& volume_params); 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 |