forked from 1b-agent/opencadstudio-upstream
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 <[email protected]>
This commit is contained in:
1 parent
8f16ba1ac2
commit
2a9416464e
2 files changed
+23
-2
No files matched your search
@@ -744,6 +744,9 @@ impl Scene {
|
||||
let mut uniforms =
|
||||
Uniforms::new(&inst.camera, full_bounds, self.document.header.lineweight_display);
|
||||
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.flat_shade = if flags.flat_shade { 1.0 } else { 0.0 };
|
||||
uniforms.transparency_enable = if self.transparency_display { 1.0 } else { 0.0 };
|
||||
|
||||
+20
-2
@@ -28,6 +28,17 @@ struct Uniforms {
|
||||
// Transparency-display toggle: 1.0 = honour baked alpha, 0.0 = force
|
||||
// every line opaque.
|
||||
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;
|
||||
|
||||
@@ -74,8 +85,15 @@ struct VertexOut {
|
||||
let which_end = which_end_arr[vid];
|
||||
let side = side_arr[vid];
|
||||
|
||||
let clip_a = u.view_proj * vec4<f32>(in.pos_a, 1.0);
|
||||
let clip_b = u.view_proj * vec4<f32>(in.pos_b, 1.0);
|
||||
// Relative-to-eye: subtract the eye (high+low) from each endpoint, then
|
||||
// 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.
|
||||
let ndc_a = clip_a.xy / clip_a.w;
|
||||
|
||||
Reference in new issue
Block a user