feat(render): relative-to-eye for the wire pipeline
The wire shader now subtracts the eye (high+low f32) per endpoint and transforms by the rotation-only view-projection instead of multiplying absolute positions by a view-projection that bakes in a large eye translation. The math is identical (proj·R·(pos−eye)) but the large eye no longer enters the f32 matrix, so lines stop jittering on pan/zoom/rotate at large (UTM) coordinates and far from world_offset. Geometry low bits are intentionally dropped: (pos − eye_high) is exact in f32 for same-magnitude operands (Sterbenz) and eye_low corrects the eye, so the only residual is a static sub-f32 position error, not motion jitter — no per-vertex low buffer needed. view_rot is cropped in lock-step with view_proj for tiled panes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8f16ba1ac2
commit
2a9416464e
2 changed files with 23 additions and 2 deletions
|
|
@ -744,6 +744,9 @@ impl Scene {
|
||||||
let mut uniforms =
|
let mut uniforms =
|
||||||
Uniforms::new(&inst.camera, full_bounds, self.document.header.lineweight_display);
|
Uniforms::new(&inst.camera, full_bounds, self.document.header.lineweight_display);
|
||||||
uniforms.view_proj = crop_view_proj(uniforms.view_proj, uo, vo, us, vs);
|
uniforms.view_proj = crop_view_proj(uniforms.view_proj, uo, vo, us, vs);
|
||||||
|
// The RTE matrix is a view-projection too, so the same clip-space crop
|
||||||
|
// applies — keep it in lock-step with view_proj for tiled / sub-rect panes.
|
||||||
|
uniforms.view_rot = crop_view_proj(uniforms.view_rot, uo, vo, us, vs);
|
||||||
uniforms.viewport_size = [visible_w, visible_h];
|
uniforms.viewport_size = [visible_w, visible_h];
|
||||||
uniforms.flat_shade = if flags.flat_shade { 1.0 } else { 0.0 };
|
uniforms.flat_shade = if flags.flat_shade { 1.0 } else { 0.0 };
|
||||||
uniforms.transparency_enable = if self.transparency_display { 1.0 } else { 0.0 };
|
uniforms.transparency_enable = if self.transparency_display { 1.0 } else { 0.0 };
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,17 @@ struct Uniforms {
|
||||||
// Transparency-display toggle: 1.0 = honour baked alpha, 0.0 = force
|
// Transparency-display toggle: 1.0 = honour baked alpha, 0.0 = force
|
||||||
// every line opaque.
|
// every line opaque.
|
||||||
transparency_enable: f32,
|
transparency_enable: f32,
|
||||||
|
_pad: vec2<f32>,
|
||||||
|
// ── Relative-to-eye (double-single) ──────────────────────────────────
|
||||||
|
// view_rot is the rotation-only view-projection; vertices subtract the eye
|
||||||
|
// (eye_high + eye_low, two f32 emulating f64) before transforming, so the
|
||||||
|
// large eye translation never enters the f32 matrix → no large-coordinate
|
||||||
|
// jitter on pan / zoom / rotate.
|
||||||
|
view_rot: mat4x4<f32>,
|
||||||
|
eye_high: vec3<f32>,
|
||||||
|
_pad_eh: f32,
|
||||||
|
eye_low: vec3<f32>,
|
||||||
|
_pad_el: f32,
|
||||||
}
|
}
|
||||||
@group(0) @binding(0) var<uniform> u: Uniforms;
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
||||||
|
|
||||||
|
|
@ -74,8 +85,15 @@ struct VertexOut {
|
||||||
let which_end = which_end_arr[vid];
|
let which_end = which_end_arr[vid];
|
||||||
let side = side_arr[vid];
|
let side = side_arr[vid];
|
||||||
|
|
||||||
let clip_a = u.view_proj * vec4<f32>(in.pos_a, 1.0);
|
// Relative-to-eye: subtract the eye (high+low) from each endpoint, then
|
||||||
let clip_b = u.view_proj * vec4<f32>(in.pos_b, 1.0);
|
// transform by the rotation-only view-projection. (pos − eye_high) is exact
|
||||||
|
// in f32 when both are the same magnitude (Sterbenz), and eye_low corrects
|
||||||
|
// the eye's sub-f32 residual — so the position tracks the camera smoothly
|
||||||
|
// at large coordinates instead of snapping onto the f32 grid each frame.
|
||||||
|
let rel_a = (in.pos_a - u.eye_high) - u.eye_low;
|
||||||
|
let rel_b = (in.pos_b - u.eye_high) - u.eye_low;
|
||||||
|
let clip_a = u.view_rot * vec4<f32>(rel_a, 1.0);
|
||||||
|
let clip_b = u.view_rot * vec4<f32>(rel_b, 1.0);
|
||||||
|
|
||||||
// NDC of both endpoints.
|
// NDC of both endpoints.
|
||||||
let ndc_a = clip_a.xy / clip_a.w;
|
let ndc_a = clip_a.xy / clip_a.w;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue