fix: selected wires always visible on top of occluding geometry

Changed selection overlay pipeline from depth_compare=Greater to
depth_compare=Always so selected wires are redrawn at full brightness
after all other passes, making them visible regardless of what is in
front of them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-04-27 03:04:31 +03:00
commit e38638502e

View file

@ -153,9 +153,9 @@ impl Pipeline {
cache: None, cache: None,
}); });
// Xray variant: only draws where fragments are BEHIND the depth buffer // Selection overlay variant: renders selected wires on top of everything
// (depth_compare=Greater), without writing depth. Used to ghost selected // (depth_compare=Always), without writing depth. Ensures selected entities
// wires through occluding geometry at reduced alpha. // are always fully visible regardless of occluding geometry.
let wire_xray_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { let wire_xray_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("wire_xray.pipeline"), label: Some("wire_xray.pipeline"),
layout: Some(&wire_layout), layout: Some(&wire_layout),
@ -173,7 +173,7 @@ impl Pipeline {
depth_stencil: Some(wgpu::DepthStencilState { depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float, format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: false, depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Greater, depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState::default(), stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(), bias: wgpu::DepthBiasState::default(),
}), }),
@ -535,12 +535,12 @@ impl Pipeline {
pub fn upload_wires(&mut self, device: &wgpu::Device, wires: &[WireModel]) { pub fn upload_wires(&mut self, device: &wgpu::Device, wires: &[WireModel]) {
self.gpu_wires = wires.iter().map(|w| WireGpu::new(device, w)).collect(); self.gpu_wires = wires.iter().map(|w| WireGpu::new(device, w)).collect();
// Ghost copies of selected wires at 25% alpha, drawn through occluding // Full-brightness copies of selected wires, drawn on top of everything
// geometry in the xray pass to keep selected entities fully visible. // in the selection overlay pass so they're always visible.
self.gpu_selected_wires = wires self.gpu_selected_wires = wires
.iter() .iter()
.filter(|w| w.selected) .filter(|w| w.selected)
.map(|w| WireGpu::new_ghost(device, w, 0.25)) .map(|w| WireGpu::new(device, w))
.collect(); .collect();
} }
@ -773,10 +773,9 @@ impl Pipeline {
} }
} }
// ── Pass 7: selected wire X-ray ghost pass ──────────────────────── // ── Pass 7: selected wire overlay pass ───────────────────────────
// Draws ghost copies of selected wires only where they are occluded // Redraws selected wires with depth_compare=Always so they appear on
// (depth_compare=Greater). Visible parts are already drawn at full // top of all other geometry at full brightness.
// brightness by the wire pass; this only reveals hidden portions.
if !self.gpu_selected_wires.is_empty() { if !self.gpu_selected_wires.is_empty() {
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("wire_xray.render_pass"), label: Some("wire_xray.render_pass"),