diff options
| author | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-09-18 19:23:11 +0300 |
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2026-09-18 21:36:44 +0300 |
| commit | 89973b5c52a967e63aecb756966d109eef209a85 (patch) | |
| tree | 884cf57762ec9f0f8709a7e76e58dbde1b854d87 /indra | |
| parent | f767219366b8dbaeea95a22bd9953a587f473298 (diff) | |
Revert "#3988 Don't render malformed sculpts"
Reverted change affects existing content. That existing content has high
impact on performance, but content is already inworld, need to find
another solution.
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llmath/llvolume.cpp | 161 | ||||
| -rw-r--r-- | indra/llmath/llvolume.h | 11 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
| -rw-r--r-- | indra/newview/llfloaterimagepreview.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llvovolume.cpp | 3 |
5 files changed, 9 insertions, 180 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 28ce4ef4b0..d4f3d1ac25 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1972,8 +1972,6 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const bool ge mNumHullIndices = 0; // set defaults - mSculptValidationCache.fill(LLSculptValidationState::Unvalidated); - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { mPathp = new LLDynamicPath(); @@ -2001,13 +1999,6 @@ void LLVolume::resizePath(S32 length) setDirty(); } -void LLVolume::setDirty() -{ - mPathp->setDirty(); - mProfilep->setDirty(); - mSculptValidationCache.fill(LLSculptValidationState::Unvalidated); -} - void LLVolume::regen() { generate(); @@ -3289,100 +3280,10 @@ S32 sculpt_sides(F32 detail) } } -static bool validate_sculpt_geometry(const LLVolume* volume, bool validate_area) -{ - if (!volume || volume->getNumVolumeFaces() == 0) - { - return true; - } - - // Validate each face in the sculpt - for (S32 face_idx = 0; face_idx < volume->getNumVolumeFaces(); ++face_idx) - { - const LLVolumeFace& face = volume->getVolumeFace(face_idx); - - // Skip validation for degenerate faces - if (face.mNumVertices < 3 || face.mNumIndices < 3) - { - continue; - } - - // Calculate 'bounding' surface - LLVector4a extent_size; - extent_size.setSub(face.mExtents[1], face.mExtents[0]); - - F32 width = extent_size[0]; - F32 height = extent_size[1]; - F32 depth = extent_size[2]; - - F32 bounding_surface = width * height + width * depth + height * depth; - bounding_surface *= 2; - - if (!llfinite(bounding_surface) || bounding_surface <= FLT_EPSILON) - { - return false; - } - - // Calculate total surface area of all triangles - F32 total_triangle_area = 0.0f; - S32 num_triangles = face.mNumIndices / 3; - - for (S32 i = 0; i < num_triangles; ++i) - { - S32 idx_base = i * 3; - U16 idx0 = face.mIndices[idx_base]; - U16 idx1 = face.mIndices[idx_base + 1]; - U16 idx2 = face.mIndices[idx_base + 2]; - - // Validate indices - if (idx0 >= face.mNumVertices || idx1 >= face.mNumVertices || idx2 >= face.mNumVertices) - { - continue; - } - - const LLVector4a& v0 = face.mPositions[idx0]; - const LLVector4a& v1 = face.mPositions[idx1]; - const LLVector4a& v2 = face.mPositions[idx2]; - - // Calculate triangle area - LLVector4a edge1, edge2, cross; - edge1.setSub(v1, v0); - edge2.setSub(v2, v0); - cross.setCross3(edge1, edge2); - - F32 triangle_area = cross.getLength3().getF32() * 0.5f; - total_triangle_area += triangle_area; - } - - if (!llfinite(total_triangle_area)) - { - return false; - } - - // The idea here is that the total area of a sculpt is normally comparable - // to the area of a bounding box. But a random overlapping collection of - // triangles has a significantly larger area than a sculpt normally has. - F32 area_ratio = total_triangle_area / bounding_surface; - constexpr F32 MAX_AREA_TO_AREA_RATIO = 16.0f; - if (validate_area && area_ratio > MAX_AREA_TO_AREA_RATIO) - { - LL_DEBUGS("LLVOLUME") << "Sculpt rejected: excessive triangle area." - << " Face index: " << face_idx - << " Total triangle area: " << total_triangle_area << " sq m" - << " Bounding surface area: " << bounding_surface << " sq m" - << " Ratio: " << area_ratio - << " Triangle count: " << num_triangles - << " Bounds: [" << width << " x " << height << " x " << depth << "]" << LL_ENDL; - return false; - } - } - - return true; -} // determine the number of vertices in both s and t direction for this sculpt -static void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) +void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) { // this code has the following properties: // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map @@ -3417,7 +3318,7 @@ static void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 deta } // sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder, bool validate_area) +void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder) { U8 sculpt_type = mParams.getSculptType(); @@ -3492,62 +3393,10 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, mSculptLevel = sculpt_level; - LLSculptValidationState cached_state = LLSculptValidationState::Valid; - if (!data_is_empty && (sculpt_level >= 0) && sculpt_level < SCULPT_CACHE_SIZE) - { - // validation might be expensive, so we do it only once per lod. - cached_state = mSculptValidationCache[sculpt_level]; - } - - switch (cached_state) - { - case LLSculptValidationState::Valid: - { - // Delete any existing faces, then regenerate - mVolumeFaces.clear(); - createVolumeFaces(); - break; - } - case LLSculptValidationState::Invalid: - { - // Invalid geometry - // Regenerate mesh with an empty placeholder - mVolumeFaces.clear(); - sculptGenerateEmptyPlaceholder(); - createVolumeFaces(); - break; - } - case LLSculptValidationState::Unvalidated: - { - // First time at this LOD - mVolumeFaces.clear(); - createVolumeFaces(); - - bool valid_geometry = true; - - // Todo: can this be backed into createVolumeFaces? - // Or calculated without having to call createVolumeFaces first? - // Todo 2: should the same be done for meshes? - valid_geometry = validate_sculpt_geometry(this, validate_area); - mSculptValidationCache[sculpt_level] = valid_geometry ? LLSculptValidationState::Valid : LLSculptValidationState::Invalid; - - if (!valid_geometry) - { - LL_WARNS("LLVOLUME") << "Sculpt failed geometry validation - either invalid image or malicious. " - << "Replacing with placeholder. Image: " << mParams.getSculptID() << LL_ENDL; - - // Clear the malicious faces - mVolumeFaces.clear(); - - // Regenerate mesh with empty placeholder - sculptGenerateEmptyPlaceholder(); + // Delete any existing faces so that they get regenerated + mVolumeFaces.clear(); - // Recreate faces with placeholder geometry - createVolumeFaces(); - } - break; - } - } //switch (cached_state) + createVolumeFaces(); } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 40e6f8e220..3496928f7b 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -60,8 +60,6 @@ class LLVolumeOctree; #include "llalignedarray.h" #include "llrigginginfo.h" -#include <array> - //============================================================================ constexpr S32 MIN_DETAIL_FACES = 6; @@ -1042,7 +1040,7 @@ public: const LLVector4a& getMeshPt(const U32 i) const { return mMesh[i]; } - void setDirty(); + void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } void regen(); void genTangents(S32 face); @@ -1095,7 +1093,7 @@ public: U32 mFaceMask; // bit array of which faces exist in this volume LLVector3 mLODScaleBias; // vector for biasing LOD based on scale - void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder, bool validate_area); + void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder); void copyVolumeFaces(const LLVolume* volume); void copyFacesTo(std::vector<LLVolumeFace> &faces) const; void copyFacesFrom(const std::vector<LLVolumeFace> &faces); @@ -1133,11 +1131,6 @@ public: bool mIsMeshAssetLoaded; bool mIsMeshAssetUnavaliable; - // Cache for sculpt geometry validation results - static constexpr S32 SCULPT_CACHE_SIZE = 6; // 0 to 5 inclusive - enum class LLSculptValidationState : S8 { Unvalidated, Valid, Invalid }; - std::array<LLSculptValidationState, SCULPT_CACHE_SIZE> mSculptValidationCache; - const LLVolumeParams mParams; LLPath *mPathp; LLProfile *mProfilep; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9484a35241..ba44b68307 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -15964,17 +15964,6 @@ <key>Value</key> <integer>1000</integer> </map> - <key>ValidateSculptyAreaRatio</key> - <map> - <key>Comment</key> - <string>Version information generated by running the viewer</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>VersionChannelName</key> <map> <key>Comment</key> diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 116286c872..bbff3e4c86 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -926,9 +926,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) if (imagep) { - static LLCachedControl<bool> validate_area(gSavedSettings, "ValidateSculptyAreaRatio", true); LLImageDataSharedLock lock(imagep); - mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false, validate_area()); + mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false); } const LLVolumeFace &vf = mVolume->getVolumeFace(0); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4a2d2da10c..076e5eb22e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1444,8 +1444,7 @@ void LLVOVolume::sculpt() } } - static LLCachedControl<bool> validate_area(gSavedSettings, "ValidateSculptyAreaRatio", true); - getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level, mSculptTexture->isMissingAsset(), validate_area()); + getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level, mSculptTexture->isMissingAsset()); } } |
