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 | 
