LOD: quadric edge collapse (Garland-Heckbert) replaces Rule A
Rule A (area-sorted triangle removal) left holes and open boundaries on closed meshes (visible artifacts when zoomed far out). The decimator is now a proper quadric edge collapse: - Collapse: welded u32 topology, per-vertex quadrics (accumulated incident face planes), edge cost = quadric error at the optimal point (clamped to the segment) + edge length, BinaryHeap with a custom Ord (f32 is not Ord; inverted compare, NaN-safe). - Standard GH semantics WITHOUT the new face: both incident pair faces degenerate and are removed; neighbouring faces remap and sweep over the region. Preserves the Euler characteristic and closedness (no holes, no books, no duplicate faces); interior collapse = -2 faces, boundary = -1. Guards: non-manifold edge (>2 faces) or a fold (duplicate sorted triple) rejects the collapse. - welded(): fuzzy welding (1e-6 relative tolerance, grid + 27- neighbour broad phase, exact verify) - trig-generated seams differ by ~1e-16, exact-bit welding missed them. - Root causes fixed along the way: dead face slots are never reused (stale edge/vface entries), vfaces updated on remap, degenerate faces dropped, best-effort target (granularity -2/-1 can land 1-2 off; soft cap, deterministic). - Docs: DRAFT D10, ROADMAP 4.3, ARCHI_CPU_GPU, gpu-driven, lib README, mesh/scene/demo comments - 'greedy decimation / Rule A' replaced by 'quadric edge collapse'. - lod.rs test: deprecated glam perspective alias -> explicit glam::camera::rh::proj::opengl::perspective. cargo test --workspace: 100 passed (94 lib + 3 wgsl + 3 integration), 0 failed; demo runs clean with LOD on.
This commit is contained in:
@@ -93,9 +93,12 @@ LOD is a **CPU-decided, GPU-executed** split (the one deliberate per-entity deci
|
||||
CPU):
|
||||
|
||||
1. **Setup (once per mesh).** Each mesh can carry up to 4 levels. Levels 1..3 are generated
|
||||
automatically from level 0 by greedy decimation (`Geometry::generate_lod_levels`): the smallest
|
||||
triangles are removed first (no edge map, no crease handling — a subset of the faces of a valid
|
||||
mesh is valid), duplicate corners are welded, and the levels are **packed into the mesh's single
|
||||
automatically from level 0 by **quadric edge collapse** (Garland–Heckbert,
|
||||
`Geometry::generate_lod_levels`): edges are ranked by quadric error and collapsed
|
||||
cheapest-first; an interior collapse merges both incident triangles (−2 faces) and remaps the
|
||||
neighbours — no new face, so a **closed mesh stays closed** (no holes, no non-manifold
|
||||
"books"), a boundary collapse removes one face; duplicate corners are welded (relative
|
||||
tolerance 1e-6), and the levels are **packed into the mesh's single
|
||||
vertex/index buffers** (see the constraint below). Level 0 is always your exact geometry.
|
||||
2. **Per frame (CPU).** For each entity, the bounding sphere used by culling is projected to screen
|
||||
pixels (its *perceived size*); that radius picks a level with **asymmetric hysteresis** — going
|
||||
|
||||
Reference in New Issue
Block a user