fix(pipeline): hatch frustum cull tests AABB in wrong space
`HatchGpu.world_aabb` was built by iterating `model.boundary` — but those vertices are stored as f32 offsets from `model.world_origin` (precision anchor for UTM-scale WCS). So the AABB was in *origin-relative* space, not the local space `view_proj` projects from. `aabb_offscreen` (Phase 2.3) then asked "is this rect near (0,0) in NDC?" instead of "is this rect at the hatch's actual position?" — which culled in-view hatches whenever the camera moved off the origin and rendered out-of-view ones near it. Sub-pixel LOD (`aabb_below_pixel`, Phase 3.3) survived because it measures a projected diagonal, which is translation-invariant. Fixes: - Add `world_origin` back when building `HatchGpu.world_aabb`, so the stored rect is in absolute local space. - 25 % margin on the viewport rect in `aabb_offscreen`, matching the wire path's `view_world_aabb` margin — keeps hatches at the edge rendered while panning. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
38f9733eb1
commit
6ae3a9d91d
2 changed files with 35 additions and 6 deletions
|
|
@ -349,11 +349,28 @@ impl HatchGpu {
|
|||
],
|
||||
});
|
||||
|
||||
// Boundary vertices are stored as f32 offsets from
|
||||
// `model.world_origin` (so f32 keeps precision at UTM-scale
|
||||
// WCS). The pipeline-level frustum cull (Phase 2.3
|
||||
// `aabb_offscreen`) projects through `view_proj`, which expects
|
||||
// local-space (world_offset-subtracted) coordinates — the same
|
||||
// space as `world_origin`. Add the origin back so `world_aabb`
|
||||
// is in that absolute local space rather than relative to the
|
||||
// anchor. (Sub-pixel LOD via `aabb_below_pixel` is unaffected:
|
||||
// it measures a projected diagonal, invariant under translation.)
|
||||
let ox = model.world_origin[0] as f32;
|
||||
let oy = model.world_origin[1] as f32;
|
||||
let world_aabb = if min_x.is_finite() && min_y.is_finite() {
|
||||
[min_x + ox, min_y + oy, max_x + ox, max_y + oy]
|
||||
} else {
|
||||
[min_x, min_y, max_x, max_y]
|
||||
};
|
||||
|
||||
Self {
|
||||
vertex_buffer,
|
||||
bind_group,
|
||||
vp_scissor: model.vp_scissor,
|
||||
world_aabb: [min_x, min_y, max_x, max_y],
|
||||
world_aabb,
|
||||
_uniform_buf,
|
||||
_boundary_buf,
|
||||
_family_buf,
|
||||
|
|
|
|||
Loading…
Reference in a new issue