mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-20 12:12:15 +00:00
wgpu backend: edge silhouette post-process (ported GL renderEdgePass)
First piece of stage 9 — the dark outlines BonsaiViewer / the GL backend
draw at depth discontinuities. Ported the GL renderEdgePass algorithm
verbatim, including the three things my earlier attempt missed:
1. Linearise depth to view-space metres before the Laplacian. Raw
[0,1] clip-z is heavily non-linear so a fixed-threshold edge
detector only caught near-camera silhouettes. Now reverses the
wgpu z-remap (z * 2 - 1 back to GL NDC) then standard reverse-
perspective to view-z.
2. Threshold scales with depth: t = EDGE_THRESHOLD * c. A 4 mm gap
between two surfaces reads the same whether it's 0.5 m or 50 m
away from the camera.
3. Multiplicative blend (Dst, Zero) with fragment output of
vec3(1 - edge). Strictly darkens, never brightens. Matches GL's
(GL_DST_COLOR, GL_ZERO) blend.
Constants EDGE_SCALE=6.0 / EDGE_THRESHOLD=0.004 are GL's tuned values.
Camera near/far hard-coded to 0.1 / 10000 (the viewport defaults);
they'll move to a small uniform when AppSettings ports across.
Pipeline state: depth-attachment-less, sample count 1, blend on, no
cull. Reuses depth_texture_'s TextureBinding usage that HiZ added.
Render pass loads the resolved main-pass colour (LoadOp_Load) and
writes back through the multiplicative blend; encoded between the main
pass and the HiZ resolve so HiZ uses the same MSAA depth that produced
the edges. edge_bind_group_ rebuilds lazily when depth_view_ is
replaced (mirrors the HiZ bind group lifecycle).
Perf cost on the 10-sidecar / 380k-instance benchmark: 0.1 ms (11.5 →
11.6 ms). Fullscreen depth-laplacian is essentially free on this GPU.
Remaining stage 9 work: HUD/labels/lines/points overlay primitives,
which need the QPainter-→-texture path. Lower visual priority than
edges; handled in a follow-up.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,9 @@ private:
|
||||
void releaseMsaaColorTexture();
|
||||
|
||||
bool buildHizPipeline();
|
||||
bool buildEdgePipeline();
|
||||
void encodeEdgePass(WGPUCommandEncoder enc, WGPUTextureView surface_view);
|
||||
void releaseEdgeResources();
|
||||
void ensureHizTextures(int viewport_w, int viewport_h);
|
||||
void releaseHizResources();
|
||||
// Resolves the just-rendered MSAA depth into the small single-sample
|
||||
@@ -247,6 +250,17 @@ private:
|
||||
// — making the pyramid 1+ frames stale, which is fine ("slightly-stale
|
||||
// depth" pattern the GL backend already documents). Two slots overlap
|
||||
// GPU write with CPU read; we never block on the readback.
|
||||
// Edge silhouette post-process (stage 9). Samples the MSAA depth
|
||||
// texture in a fullscreen pass, computes a depth Laplacian, blends
|
||||
// dark lines into the resolved surface colour. Matches GL's
|
||||
// renderEdgePass() visually.
|
||||
WGPUShaderModule edge_shader_module_ = nullptr;
|
||||
WGPUBindGroupLayout edge_bgl_ = nullptr;
|
||||
WGPUPipelineLayout edge_pipeline_layout_ = nullptr;
|
||||
WGPURenderPipeline edge_pipeline_ = nullptr;
|
||||
WGPUBindGroup edge_bind_group_ = nullptr;
|
||||
bool edges_enabled_ = true;
|
||||
|
||||
enum class HizSlotState : uint8_t { Idle, Mapping, Mapped };
|
||||
static constexpr int HIZ_SLOTS = 2;
|
||||
WGPUBuffer hiz_staging_buffers_[HIZ_SLOTS] = { nullptr, nullptr };
|
||||
|
||||
Reference in New Issue
Block a user