forked from 1b-agent/opencadstudio-upstream
feat(pipeline): per-instance visibility for batched hatches (Phase 4-B, step 4)
Adds a dedicated `visibility: array<u32>` storage buffer (binding 4) alongside the existing batched hatch buffers. Vertex shader reads `visibility[v.instance_index]` — 0 → emit an out-of-NDC clip position so the GPU rasterizer clips the primitive before the fragment stage runs. `compute_hatch_lod` now drives this buffer instead of (or alongside, for the per-hatch fallback) `hatch_skip_flags`. Walks a per-instance CPU AABB mirror that the builder fills at upload time (`instance_aabbs`), applies the same `aabb_below_pixel` (sub-pixel LOD) OR `aabb_offscreen` (frustum cull) rule the legacy path used, and pushes the resulting 0/1 flags via `queue.write_buffer` on a separate 4 B-per-hatch buffer — ~40 KB per pan tick for 10 k hatches, far cheaper than re-writing the 112 B-per-instance data. Step 5 will remove the legacy `gpu_hatches` Vec, the per-hatch draw loop, and `hatch_skip_flags` once the batched path has soaked. Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
cfe53bd789
commit
398eee551d
4 files changed
+99
-19
No files matched your search
@@ -63,10 +63,15 @@ struct LineFamily {
|
||||
dash_offset: u32,
|
||||
}
|
||||
|
||||
@group(1) @binding(0) var<storage, read> instances: array<HatchInstance>;
|
||||
@group(1) @binding(1) var<storage, read> boundary: array<vec4<f32>>;
|
||||
@group(1) @binding(2) var<storage, read> families: array<LineFamily>;
|
||||
@group(1) @binding(3) var<storage, read> dashes: array<f32>;
|
||||
@group(1) @binding(0) var<storage, read> instances: array<HatchInstance>;
|
||||
@group(1) @binding(1) var<storage, read> boundary: array<vec4<f32>>;
|
||||
@group(1) @binding(2) var<storage, read> families: array<LineFamily>;
|
||||
@group(1) @binding(3) var<storage, read> dashes: array<f32>;
|
||||
// Per-instance visibility (Phase 4-B sub-pixel + frustum skip).
|
||||
// CPU writes `1` to draw / `0` to skip every frame; vertex shader
|
||||
// emits an out-of-NDC clip position for 0-instances so the GPU
|
||||
// rasterizer culls the primitive before any fragment runs.
|
||||
@group(1) @binding(4) var<storage, read> visibility: array<u32>;
|
||||
|
||||
// ── Vertex shader ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -100,12 +105,12 @@ fn corner_xy(c: u32, aabb: vec4<f32>) -> vec2<f32> {
|
||||
var o: VOut;
|
||||
let inst = instances[v.instance_index];
|
||||
|
||||
// CPU-driven visibility flag (Phase 4-B frustum skip). Emit a clip
|
||||
// position whose x/y exceed |w|, so the GPU frustum-culls the
|
||||
// primitive and no fragment runs for it. (WGSL forbids literal NaN
|
||||
// so we can't go that route; pushing the vertex out of the unit
|
||||
// cube is the equivalent degenerate-triangle trick.)
|
||||
if inst.visible == 0u {
|
||||
// Per-frame visibility (CPU-driven sub-pixel + frustum skip).
|
||||
// 0 → emit a clip position whose x/y exceed |w| so the GPU
|
||||
// frustum-culls the primitive and no fragment runs. (WGSL
|
||||
// forbids literal NaN so this out-of-NDC trick replaces the
|
||||
// usual NaN-degenerate-triangle.)
|
||||
if visibility[v.instance_index] == 0u {
|
||||
o.clip = vec4<f32>(2.0, 2.0, 2.0, 1.0);
|
||||
o.xz = vec2<f32>(0.0, 0.0);
|
||||
o.instance_index = v.instance_index;
|
||||
|
||||
Reference in new issue
Block a user