feat(render): double-single vertex positions for the wire pipeline

Vertices now carry the low residual alongside the high half all the way
to the GPU: tessellation splits the offset-relative f64 coordinate into
(high, low) f32 (TruckTessResult::Lines/Point, the Text path, Lines /
SegmentedLines, and the block-cache instance transform), WireModel and
the block batch carry a paired points_low buffer, WireInstance gains
pos_a_low/pos_b_low (locations 10/11), and wire.wgsl reconstructs
rel = (pos_high - eye_high) + (pos_low - eye_low).

This is the piece the camera-only RTE was missing: at UTM-scale
coordinates the single-f32 vertex was quantized to ~0.5 m, so it snapped
each time the eye crossed an f32 boundary on pan. With the low half the
position is exact and the cross-drawing-paste jitter is gone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-23 17:44:09 +03:00
commit 6a74f12a92
6 changed files with 237 additions and 151 deletions

View file

@ -104,13 +104,22 @@ pub fn edge_wires(solid: &Solid) -> Vec<acadrust::entities::Wire> {
let mut wires = Vec::new();
for shell in solid.boundaries() {
for edge in shell.edge_iter() {
if let TruckTessResult::Lines(pts) = tessellate_edge(&edge, [0.0; 3]) {
if let TruckTessResult::Lines(pts, pts_low) =
tessellate_edge(&edge, [0.0; 3])
{
if pts.len() < 2 {
continue;
}
let pts3: Vec<Vector3> = pts
.iter()
.map(|p| Vector3::new(p[0] as f64, p[1] as f64, p[2] as f64))
.zip(pts_low.iter())
.map(|(p, l)| {
Vector3::new(
p[0] as f64 + l[0] as f64,
p[1] as f64 + l[1] as f64,
p[2] as f64 + l[2] as f64,
)
})
.collect();
wires.push(acadrust::entities::Wire::from_points(pts3));
}