|
Wildmeshing Toolkit
|
Weights and policy for smooth_vertex_3d. More...
#include <SmoothVertex.hpp>
Public Types | |
| enum class | SmoothingMode { Projected , Exact } |
Public Attributes | |
| double | w_amips = 1e-4 |
| double | w_envelope = 1.0 - 1e-4 |
| double | s_amips = 1.0 |
| double | s_envelope = 1.0 |
| bool | two_stage = true |
| bool | quality_veto_on_surface = true |
| SmoothingMode | smoothing_mode = SmoothingMode::Projected |
| int | project_line_search_steps = 12 |
| int | project_line_search_nested_steps = 0 |
Weights and policy for smooth_vertex_3d.
The weights follow simwild's convention: w_envelope = 1 - w_amips, with w_amips small (1e-4), so the envelope term dominates and the AMIPS term acts as a light quality preference. The scale factors put the two on a comparable footing — AMIPS is dimensionless while the envelope energy is a squared distance, so s_envelope is 1 / eps^2 and the term reads (d/eps)^2: distance in envelope widths, dimensionless like AMIPS in both 2D and 3D.
|
strong |
How a surface vertex is placed.
Projected: smooth as if interior (AMIPS alone), then walk back toward the start along t = 1, 1/2, 1/4, ..., projecting each candidate onto the input; take the first projected candidate that does not invert and strictly lowers the worst incident element, else do not move. The vertex lands exactly on the input; no weights exist.
Exact: minimize w_amips * AMIPS + w_envelope * (d/eps)^2 with the TRUE Hessian of the distance to the piecewise-linear input (ExactDistanceEnergy2D/3D): sliding is free exactly where the input is flat, blocked isotropically at corners and vertices, constrained to the direction of a 3D edge or curve segment. The vertex rests a w_amips-proportional distance off the input; the accept checks below apply either way.
| int wmtk::optimization::SmoothVertexOptions::project_line_search_nested_steps = 0 |
Second pass, run only when the first found nothing: partial projections.
The first pass only ever tests points ON the input, so a vertex whose one-ring cannot tolerate being pulled all the way there is refused at every step and does not move at all – and is refused again next pass, from the same place. This pass revisits each candidate and bisects between the interpolated point and its projection, taking the longest step toward the input that still does not invert and still lowers the worst element. The vertex ends up off the input, but closer to it than it was, so the next pass starts from somewhere better and it converges onto the surface over several passes instead of being stuck forever.
0 disables the pass. Costs nothing when the first pass succeeds, which is the common case.
| int wmtk::optimization::SmoothVertexOptions::project_line_search_steps = 12 |
Backtracking steps tried before the move is abandoned: t = 1, 1/2, ..., 2^-(n-1). Exhausting these without an acceptable candidate is what "the search failed" means.
| bool wmtk::optimization::SmoothVertexOptions::quality_veto_on_surface = true |
Refuse a move that makes the worst incident element worse. Applied to every vertex.
This used to be false for SURFACE vertices, on the grounds that vetoing them deadlocks a mesh whose surface vertices have drifted: the envelope pulls such a vertex back, the pull worsens some incident element, the move is refused, and the vertex never returns.
That reasoning was sound but conditional – it described a mesh built against an envelope of eps/2, where surface vertices had drifted most of the way to the wall (a population of ~100 sitting at 0.5-0.8 eps on Thingi10K 101954, never returning). With the whole eps the drift is gone, the vertices start near the input, and the veto costs them nothing.
What it buys is large. Without it, smoothing raised the max energy in 38% of passes, and a mesh that had descended to ~10.5 would then oscillate in a 10-13 band for tens of iterations until a reading happened to fall below the target – convergence by random walk. Over 31 models (14 Thingi10K + 17 triwild20k, stop_energy 10) turning it on cut total iterations from 691 to 350 with no model regressing by more than one iteration and none left above target: triwild20k 166331 78 -> 13, 191265 58 -> 8, 191874 58 -> 15, 202302 47 -> 12.
A narrower form was tried and does not work: refusing only moves that create a new GLOBAL worst element still lets a pass fill the mesh with elements just under the current worst, which a later topology pass tips over. Bounding the maximum does not bound the degradation (191265: 42 iterations against 58 baseline and 8 with the full veto).
| bool wmtk::optimization::SmoothVertexOptions::two_stage = true |
Solve once with reciprocal weights before the weighted solve. Cheap warm-up that gets the vertex into the right basin before the envelope term dominates.