Skip to content

Commit 05befa7

Browse files
authored
Merge pull request #987 from zeux/clod-edge
demo: Add optional error clamping based on edge lengths to clusterlod.h
2 parents f6fd69d + d608f06 commit 05befa7

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

demo/clusterlod.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,19 @@ struct clodConfig
4242
// amplify the error of clusters that go through sloppy simplification to account for appearance degradation
4343
float simplify_error_factor_sloppy;
4444

45+
// experimental: limit error by edge length, aiming to remove subpixel triangles even if the attribute error is high
46+
float simplify_error_edge_limit;
47+
4548
// use permissive simplification instead of regular simplification (make sure to use attribute_protect_mask if this is set!)
4649
bool simplify_permissive;
4750

4851
// use permissive or sloppy simplification but only if regular simplification gets stuck
4952
bool simplify_fallback_permissive;
5053
bool simplify_fallback_sloppy;
5154

55+
// use regularization during simplification to make triangle density more uniform, at some cost to overall triangle count; recommended for deformable objects
56+
bool simplify_regularize;
57+
5258
// should clodCluster::bounds be computed based on the geometry of each cluster
5359
bool optimize_bounds;
5460

@@ -422,7 +428,7 @@ static std::vector<unsigned int> simplify(const clodConfig& config, const clodMe
422428

423429
std::vector<unsigned int> lod(indices.size());
424430

425-
unsigned int options = meshopt_SimplifySparse | meshopt_SimplifyErrorAbsolute | (config.simplify_permissive ? meshopt_SimplifyPermissive : 0);
431+
unsigned int options = meshopt_SimplifySparse | meshopt_SimplifyErrorAbsolute | (config.simplify_permissive ? meshopt_SimplifyPermissive : 0) | (config.simplify_regularize ? meshopt_SimplifyRegularize : 0);
426432

427433
lod.resize(meshopt_simplifyWithAttributes(&lod[0], &indices[0], indices.size(),
428434
mesh.vertex_positions, mesh.vertex_count, mesh.vertex_positions_stride,
@@ -442,6 +448,36 @@ static std::vector<unsigned int> simplify(const clodConfig& config, const clodMe
442448
*error *= config.simplify_error_factor_sloppy; // scale error up to account for appearance degradation
443449
}
444450

451+
// optionally limit error by edge length, aiming to remove subpixel triangles even if the attribute error is high
452+
if (config.simplify_error_edge_limit > 0)
453+
{
454+
float max_edge_sq = 0;
455+
456+
for (size_t i = 0; i < indices.size(); i += 3)
457+
{
458+
unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
459+
assert(a < mesh.vertex_count && b < mesh.vertex_count && c < mesh.vertex_count);
460+
461+
const float* va = &mesh.vertex_positions[a * (mesh.vertex_positions_stride / sizeof(float))];
462+
const float* vb = &mesh.vertex_positions[b * (mesh.vertex_positions_stride / sizeof(float))];
463+
const float* vc = &mesh.vertex_positions[c * (mesh.vertex_positions_stride / sizeof(float))];
464+
465+
// compute squared edge lengths
466+
float eab = (va[0] - vb[0]) * (va[0] - vb[0]) + (va[1] - vb[1]) * (va[1] - vb[1]) + (va[2] - vb[2]) * (va[2] - vb[2]);
467+
float eac = (va[0] - vc[0]) * (va[0] - vc[0]) + (va[1] - vc[1]) * (va[1] - vc[1]) + (va[2] - vc[2]) * (va[2] - vc[2]);
468+
float ebc = (vb[0] - vc[0]) * (vb[0] - vc[0]) + (vb[1] - vc[1]) * (vb[1] - vc[1]) + (vb[2] - vc[2]) * (vb[2] - vc[2]);
469+
470+
float emax = std::max(std::max(eab, eac), ebc);
471+
float emin = std::min(std::min(eab, eac), ebc);
472+
473+
// we prefer using min edge length to reduce the number of triangles <1px thick, but need some stopgap for thin and long triangles like wires
474+
max_edge_sq = std::max(max_edge_sq, std::max(emin, emax / 4));
475+
}
476+
477+
// adjust the error to limit it for dense clusters based on edge lengths
478+
*error = std::min(*error, sqrtf(max_edge_sq) * config.simplify_error_edge_limit);
479+
}
480+
445481
return lod;
446482
}
447483

0 commit comments

Comments
 (0)