From 4ae6f32ee16b21aed2235e96b99e18eebfdd82c6 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Tue, 15 Nov 2016 20:16:01 +0200 Subject: MAINT-6901 Fixes upload assigning different scale to parts of the model --- indra/llprimitive/lldaeloader.cpp | 13 ++-- indra/llprimitive/llmodel.cpp | 159 ++++++++++++++++++++++++++++++++++++++ indra/llprimitive/llmodel.h | 1 + 3 files changed, 165 insertions(+), 8 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 031befe63a..de02c5c188 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -999,6 +999,11 @@ bool LLDAELoader::OpenFile(const std::string& filename) std::sort(mModelList.begin(), mModelList.end(), ModelSort()); + if (!mNoNormalize) + { + LLModel::normalizeModels(mModelList); + } + model_list::iterator model_iter = mModelList.begin(); while (model_iter != mModelList.end()) { @@ -2408,8 +2413,6 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector& mo // ret->sortVolumeFacesByMaterialName(); - bool normalized = false; - int submodelID = 0; // remove all faces that definitely won't fit into one model and submodel limit @@ -2424,12 +2427,6 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector& mo { // Insure we do this once with the whole gang and not per-model // - if (!normalized && !mNoNormalize) - { - normalized = true; - ret->normalizeVolumeFaces(); - } - ret->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder); if (!mNoOptimize) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index e494c55250..3270722ccb 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -174,6 +174,165 @@ void LLModel::trimVolumeFacesToSize(U32 new_count, LLVolume::face_list_t* remain } } +// Shrink group of models to fit +// on a 1x1x1 cube centered at the origin. +void LLModel::normalizeModels(std::vector> model_list) +{ + std::vector >::iterator iter = model_list.begin(); + + LLVector4a min, max; + while (iter != model_list.end() && (*iter)->mVolumeFaces.empty()) + { + iter++; + } + if (iter == model_list.end()) + { + // no models with faces + return; + } + + min = (*iter)->mVolumeFaces[0].mExtents[0]; + max = (*iter)->mVolumeFaces[0].mExtents[1]; + + // Treat models as a group - each model out of 1x1x1 cube + // needs scaling and will affect whole group scale + while (iter != model_list.end()) + { + LLPointer model = *iter++; + + if (model.get() && model->mVolumeFaces.empty()) + { + // For all of the volume faces + // in the model, loop over + // them and see what the extents + // of the volume along each axis. + + for (U32 i = 0; i < model->mVolumeFaces.size(); ++i) + { + LLVolumeFace& face = model->mVolumeFaces[i]; + + update_min_max(min, max, face.mExtents[0]); + update_min_max(min, max, face.mExtents[1]); + + if (face.mTexCoords) + { + LLVector2& min_tc = face.mTexCoordExtents[0]; + LLVector2& max_tc = face.mTexCoordExtents[1]; + + min_tc = face.mTexCoords[0]; + max_tc = face.mTexCoords[0]; + + for (U32 j = 1; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, face.mTexCoords[j]); + } + } + else + { + face.mTexCoordExtents[0].set(0, 0); + face.mTexCoordExtents[1].set(1, 1); + } + } + } + } + + // Now that we have the extents of the model + // we can compute the offset needed to center + // the model at the origin. + + // Compute center of the model + // and make it negative to get translation + // needed to center at origin. + LLVector4a trans; + trans.setAdd(min, max); + trans.mul(-0.5f); + + // Compute the total size along all + // axes of the model. + LLVector4a size; + size.setSub(max, min); + + // Prevent division by zero. + F32 x = size[0]; + F32 y = size[1]; + F32 z = size[2]; + F32 w = size[3]; + if (fabs(x) < F_APPROXIMATELY_ZERO) + { + x = 1.0; + } + if (fabs(y) < F_APPROXIMATELY_ZERO) + { + y = 1.0; + } + if (fabs(z) < F_APPROXIMATELY_ZERO) + { + z = 1.0; + } + size.set(x, y, z, w); + + // Compute scale as reciprocal of size + LLVector4a scale; + scale.splat(1.f); + scale.div(size); + + LLVector4a inv_scale(1.f); + inv_scale.div(scale); + + iter = model_list.begin(); + // apply fixed scale and trans to all models as a single group + while (iter != model_list.end()) + { + LLPointer model = *iter++; + + if (model->mVolumeFaces.empty()) + { + continue; + } + + for (U32 i = 0; i < model->mVolumeFaces.size(); ++i) + { + LLVolumeFace& face = model->mVolumeFaces[i]; + + // We shrink the extents so + // that they fall within + // the unit cube. + face.mExtents[0].add(trans); + face.mExtents[0].mul(scale); + + face.mExtents[1].add(trans); + face.mExtents[1].mul(scale); + + // For all the positions, we scale + // the positions to fit within the unit cube. + LLVector4a* pos = (LLVector4a*)face.mPositions; + LLVector4a* norm = (LLVector4a*)face.mNormals; + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + pos[j].add(trans); + pos[j].mul(scale); + if (norm && !norm[j].equals3(LLVector4a::getZero())) + { + norm[j].mul(inv_scale); + norm[j].normalize3(); + } + } + } + + // mNormalizedScale is the scale at which + // we would need to multiply the model + // by to get the original size of the + // model instead of the normalized size. + LLVector4a normalized_scale; + normalized_scale.splat(1.f); + normalized_scale.div(scale); + model->mNormalizedScale.set(normalized_scale.getF32ptr()); + model->mNormalizedTranslation.set(trans.getF32ptr()); + model->mNormalizedTranslation *= -1.f; + } +} + // Shrink the model to fit // on a 1x1x1 cube centered at the origin. // The positions and extents diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index ae602c09df..8fe025a352 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -172,6 +172,7 @@ public: void addFace(const LLVolumeFace& face); void sortVolumeFacesByMaterialName(); + static void normalizeModels(std::vector> model_list); void normalizeVolumeFaces(); void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL); void optimizeVolumeFaces(); -- cgit v1.2.3