Variable unifyTriangleWindingConst

unifyTriangleWinding: Fix = ...

Auto-fix for GEOMETRY_INCONSISTENT_WINDING — flood-fills triangle winding from a seed, flipping every triangle whose shared edge runs the same direction as its source neighbour (i.e. winds the wrong way relative to the seed).

Algorithm:

  1. Build an undirected-edge → adjacent-triangle map.
  2. Pick triangle 0 as the seed (assumed correct winding).
  3. DFS through neighbours: for each unvisited triangle that shares an edge with the current one, look at the post-flip directed edges of both. If they traverse the shared edge in the same direction, mark the neighbour as needing a flip.
  4. Repeat from each unvisited triangle to handle disconnected components.
  5. Rewrite geom.indices: triangles flagged for flip get their last two indices swapped (i0,i1,i2i0,i2,i1).

Vertex normals don't need updating — smooth normals are direction-independent of the per-triangle winding that produced them. edgeIndices is undirected, also untouched.

Caveat — seed selection. If more than half of the original triangles were wound wrong, the seed is one of those wrong triangles, and the fix flips the correct half to match. The resulting mesh is consistently wound but inside-out. Re-run the inspection: GEOMETRY_INCONSISTENT_WINDING will be silent (consistent) but visual inspection will show the model rendering back-faces. In that case the user can apply the fix again with the index ordering reversed (manual triage) or re-author the model upstream.

Idempotent: returns {fixed: false} on a non-triangle primitive, missing indices, or a mesh that already has every directed edge unique.