# Conflicts:
#	autobuild.xml
#	indra/newview/lldrawpoolavatar.cpp
#	indra/newview/llfloatermodelpreview.cpp
#	indra/newview/llspatialpartition.h
#	indra/newview/llvovolume.cpp
master
Ansariel 2022-03-02 10:31:44 +01:00
commit cc95d520b4
4 changed files with 113 additions and 32 deletions

View File

@ -850,7 +850,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
{
const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
U32 count = mpc.mMatrixPalette.size();
if (count == 0)

View File

@ -1417,6 +1417,11 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
size_vertices += face.mNumVertices;
}
if (size_indices < 3)
{
return -1;
}
// Allocate buffers, note that we are using U32 buffer instead of U16
U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
@ -1461,10 +1466,10 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
// Now that we have buffers, optimize
S32 target_indices = 0;
F32 result_code = 0; // how far from original the model is, 1 == 100%
F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplifyU32(
output_indices,
combined_indices,
@ -1475,17 +1480,27 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
target_indices,
error_threshold,
sloppy,
&result_code);
&result_error);
if (result_code < 0)
if (result_error < 0)
{
LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " original count: " << size_indices << LL_ENDL;
}
if (new_indices < 3)
{
// Model should have at least one visible triangle
ll_aligned_free<64>(combined_positions);
ll_aligned_free_32(output_indices);
ll_aligned_free_32(combined_indices);
return -1;
}
// repack back into individual faces
LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
@ -1638,16 +1653,20 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
{
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
S32 size_indices = face.mNumIndices;
if (size_indices < 3)
{
return -1;
}
// todo: do not allocate per each face, add one large buffer somewhere
// faces have limited amount of indices
S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
U16* output = (U16*)ll_aligned_malloc_16(size);
S32 target_indices = 0;
F32 result_code = 0; // how far from original the model is, 1 == 100%
F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplify(
output,
face.mIndices,
@ -1658,12 +1677,12 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
target_indices,
error_threshold,
sloppy,
&result_code);
&result_error);
if (result_code < 0)
if (result_error < 0)
{
LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
<< " of model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
@ -1875,21 +1894,21 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Run meshoptimizer for each face
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0)
{
// Sloppy failed and returned an invalid model
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
}
}
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
<< " simplified using per face method." << LL_ENDL;
}
if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
{
// Switches between 'combine' method and 'per model sloppy' based on combine's result.
// Switches between 'combine' method and 'sloppy' based on combine's result.
F32 allowed_ratio_drift = 2.f;
F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
if (res_ratio < 0)
F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
if (precise_ratio < 0)
{
// U16 vertices overflow, shouldn't happen, but just in case
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@ -1897,42 +1916,101 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
}
}
else if (res_ratio * allowed_ratio_drift < indices_decimator)
else if (precise_ratio * allowed_ratio_drift < indices_decimator)
{
// Try sloppy variant if normal one failed to simplify model enough.
res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
// Sloppy variant can fail entirely and has issues with precision,
// so code needs to do multiple attempts with different decimators.
// Todo: this is a bit of a mess, needs to be refined and improved
F32 last_working_decimator = 0.f;
F32 last_working_ratio = F32_MAX;
F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
if (sloppy_ratio > 0)
{
// Would be better to do a copy of target_model here, but if
// we need to use sloppy decimation, model should be cheap
// and fast to generate and it won't affect end result
last_working_decimator = indices_decimator;
last_working_ratio = sloppy_ratio;
}
// Sloppy has a tendecy to error into lower side, so a request for 100
// triangles turns into ~70, so check for significant difference from target decimation
F32 sloppy_ratio_drift = 1.4f;
if (lod_mode == LIMIT_TRIANGLES
&& (res_ratio > indices_decimator * sloppy_ratio_drift || res_ratio < 0))
&& (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0))
{
// Apply a correction to compensate.
// (indices_decimator / res_ratio) by itself is likely to overshoot to a differend
// side due to overal lack of precision, and we don't need an ideal result, which
// likely does not exist, just a better one, so a partial correction is enough.
F32 sloppy_decimator = indices_decimator * (indices_decimator / res_ratio + 1) / 2;
res_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
}
if (res_ratio < 0)
if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
{
// Sloppy variant failed to generate triangles.
// Compensation didn't work, return back to previous decimator
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
}
if (sloppy_ratio < 0)
{
// Sloppy method didn't work, try with smaller decimation values
S32 size_vertices = 0;
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
const LLVolumeFace &face = base->getVolumeFace(face_idx);
size_vertices += face.mNumVertices;
}
// Complex models aren't supposed to get here, they are supposed
// to work on a first try of sloppy due to having more viggle room.
// If they didn't, something is likely wrong, no point locking the
// thread in a long calculation that will fail.
const U32 too_many_vertices = 27000;
if (size_vertices > too_many_vertices)
{
LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL;
}
else
{
// Find a decimator that does work
F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3
F32 sloppy_decimator = indices_decimator / sloppy_decimation_step;
while (sloppy_ratio < 0
&& sloppy_decimator > precise_ratio
&& sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
{
sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
}
}
}
if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio)
{
// Sloppy variant failed to generate triangles or is worse.
// Can happen with models that are too simple as is.
// Fallback to normal method or use lower decimator.
genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
// Fallback to normal method
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
<< " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
else
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
<< " resulting ratio " << sloppy_ratio
<< " sloppily simplified using per model method." << LL_ENDL;
}
}
@ -1940,6 +2018,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
<< " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
}

View File

@ -40,6 +40,8 @@
#include "llface.h"
#include "llviewercamera.h"
#include "llvector4a.h"
#include "llvoavatar.h"
//<FS:Beq> needed to resolve render_hull dep
#include "llmodel.h"
//</FS:Beq>
@ -136,7 +138,7 @@ public:
F32 mAlphaMaskCutoff;
U8 mDiffuseAlphaMode;
bool mSelected;
LLVOAvatar* mAvatar = nullptr;
LLPointer<LLVOAvatar> mAvatar = nullptr;
LLMeshSkinInfo* mSkinInfo = nullptr;

View File

@ -926,7 +926,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
void LLViewerParcelMgr::render()
{
if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)
{
// Rendering is done in agent-coordinates, so need to supply
// an appropriate offset to the render code.