fix(renderer): keep draw-order offsets within clipping planes

This commit is contained in:
Christopher Overbeck committed 2026-09-15 12:36:05 -05:00
1 parent 0e42e3bf28
commit e52e565b1f
26 files changed
+525 -90

No files matched your search

+1 -4
View File
@@ -28,16 +28,13 @@ struct VertexOut {
@location(0) color: vec4<f32>,
}
const DRAW_ORDER_BIAS: f32 = 0.001;
@vertex
fn vs_main(v: VertexIn) -> VertexOut {
var out: VertexOut;
let rel = (v.position + v.translation - u.eye_high)
+ (v.position_low + v.translation_low - u.eye_low);
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
out.clip_pos.z = out.clip_pos.z
- (v.source_depth + v.instance_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
out.clip_pos = apply_draw_order(out.clip_pos, v.source_depth + v.instance_depth);
out.color = v.color;
return out;
}
+1 -4
View File
@@ -32,16 +32,13 @@ struct VertOut {
@location(1) color: vec4<f32>,
}
const DRAW_ORDER_BIAS: f32 = 0.001;
@vertex
fn vs_main(v: VertIn) -> VertOut {
var out: VertOut;
let rel = (v.pos + v.translation - u.eye_high)
+ (v.pos_low + v.translation_low - u.eye_low);
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
out.clip_pos.z = out.clip_pos.z
- (v.source_depth + v.instance_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
out.clip_pos = apply_draw_order(out.clip_pos, v.source_depth + v.instance_depth);
out.uv = v.uv;
out.color = v.color;
return out;
+2 -3
View File
@@ -44,7 +44,6 @@ struct VertexIn {
@location(8) depth: vec2<f32>,
}
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
@@ -165,7 +164,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
let pos_rel = mix(rel_a, rel_b, which_end);
let world_pos = pos_rel + perp_world * (eff_hw * side);
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
clip_pos.z = clip_pos.z - in.depth.x * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, in.depth.x);
final_clip = clip_pos;
out_dist = mix(in.distances.x, in.distances.y, which_end);
@@ -192,7 +191,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
+ direction * half_width * extension;
let ndc_offset = offset_px / (u.viewport_size * 0.5);
var clip_pos_out = clip_position + vec4<f32>(ndc_offset * clip_position.w, 0.0, 0.0);
clip_pos_out.z = clip_pos_out.z - in.depth.x * DRAW_ORDER_BIAS * clip_pos_out.w;
clip_pos_out = apply_draw_order(clip_pos_out, in.depth.x);
final_clip = clip_pos_out;
out_dist = mix(in.distances.x, in.distances.y, which_end)
+2 -3
View File
@@ -68,7 +68,6 @@ struct VertexIn {
@location(8) depth: vec2<f32>,
}
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
@@ -196,7 +195,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
let pos_rel = mix(rel_a, rel_b, which_end);
let world_pos = pos_rel + perp_world * (eff_hw * side);
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
clip_pos.z = clip_pos.z - in.depth.x * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, in.depth.x);
final_clip = clip_pos;
out_dist = mix(seg_distances.x, seg_distances.y, which_end);
@@ -223,7 +222,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
+ direction * half_width * extension;
let ndc_offset = offset_px / (u.viewport_size * 0.5);
var clip_pos_out = clip_position + vec4<f32>(ndc_offset * clip_position.w, 0.0, 0.0);
clip_pos_out.z = clip_pos_out.z - in.depth.x * DRAW_ORDER_BIAS * clip_pos_out.w;
clip_pos_out = apply_draw_order(clip_pos_out, in.depth.x);
final_clip = clip_pos_out;
out_dist = mix(seg_distances.x, seg_distances.y, which_end)
+1 -2
View File
@@ -26,7 +26,6 @@ struct Uniforms {
}
@group(0) @binding(0) var<uniform> u: Uniforms;
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
const TAU: f32 = 6.283185307179586;
@@ -116,7 +115,7 @@ fn resolve_px_hw(px_hw: f32) -> f32 {
let world_pos_rel = center_rel + (u_val * axis_x + v_val * axis_y) * ext;
var clip_pos = u.view_rot * vec4<f32>(world_pos_rel, 1.0);
clip_pos.z = clip_pos.z - draw_depth * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, draw_depth);
var out: VertexOut;
out.clip_pos = clip_pos;
+13
View File
@@ -0,0 +1,13 @@
// Positive order draws in front; zero retains geometric depth. Keep the usual
// 0.001 NDC offset away from the clipping planes, but reduce it near either
// plane: perspective depth can be much closer to 1 than this fixed offset.
//
// Using order / (1 + abs(order)) for the limited region keeps ordering monotonic
// (including the paper background's -2). Less than half the remaining depth is
// consumed, so valid vertices stay valid. Out-of-range/behind-eye vertices get
// no offset and remain subject to the real near/far clipping planes.
fn apply_draw_order(clip: vec4<f32>, order: f32) -> vec4<f32> {
let room = 0.5 * max(0.0, min(clip.z, clip.w - clip.z));
let scale = min(0.001 * max(clip.w, 0.0), room / (1.0 + abs(order)));
return vec4<f32>(clip.xy, clip.z - order * scale, clip.w);
}
+1 -2
View File
@@ -21,7 +21,6 @@ struct Uniforms {
}
@group(0) @binding(0) var<uniform> u: Uniforms;
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
const TAU: f32 = 6.283185307179586;
@@ -98,7 +97,7 @@ fn resolve_hw(px_hw: f32) -> f32 {
let world_pos_rel = center_rel + (u_val * ext_u) * u_axis + (v_val * ext_v) * v_axis;
var clip_pos = u.view_rot * vec4<f32>(world_pos_rel, 1.0);
clip_pos.z = clip_pos.z - draw_depth * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, draw_depth);
var out: VertexOut;
out.clip_pos = clip_pos;
+2 -3
View File
@@ -34,17 +34,16 @@ struct VertexOut {
@location(0) color: vec4<f32>,
};
// Draw-order depth bias (see wire.wgsl). Signed draw_depth; 0.0 (all 3D
// Draw-order depth bias (see draw_order.wgsl). Signed draw_depth; 0.0 (all 3D
// surface faces — 3DFACE, PolyfaceMesh, PolygonMesh) leaves real depth
// untouched so they occlude against solids; only 2D fills order by rank.
const DRAW_ORDER_BIAS: f32 = 0.001;
@vertex
fn vs_main(v: VertexIn) -> VertexOut {
var out: VertexOut;
let rel = (v.position - u.eye_high) + (v.position_low - u.eye_low);
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
out.clip_pos.z = out.clip_pos.z - v.draw_depth * DRAW_ORDER_BIAS * out.clip_pos.w;
out.clip_pos = apply_draw_order(out.clip_pos, v.draw_depth);
out.color = v.color;
return out;
}
+1 -5
View File
@@ -47,9 +47,6 @@ struct HatchInstance {
grad_kind: u32, // shape (0=linear,1=cyl,2=sph,3=hemi,4=curved), bit4=invert
}
// Draw-order depth bias (see wire.wgsl). Higher draw_depth → smaller z →
// drawn on top, ordering this fill against other entity types.
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
@@ -122,8 +119,7 @@ struct VOut {
local.y + inst.world_origin_low.y + v.translation_low.y - u.eye_low.y,
-u.eye_low.z);
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
o.clip.z = o.clip.z
- (inst.draw_depth + v.draw_depth) * DRAW_ORDER_BIAS * o.clip.w;
o.clip = apply_draw_order(o.clip, inst.draw_depth + v.draw_depth);
o.xz = local;
o.instance_index = v.instance_index;
return o;
+1 -1
View File
@@ -110,7 +110,7 @@ struct VOut {
v.pos.y + h.origin_low.y + v.translation_low.y - u.eye_low.y,
v.pos.z - u.eye_low.z);
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
o.clip.z = o.clip.z - v.draw_depth * 0.001 * o.clip.w;
o.clip = apply_draw_order(o.clip, v.draw_depth);
o.xz = vec2<f32>(v.pos.x, v.pos.y);
return o;
}
+1 -5
View File
@@ -33,9 +33,6 @@ struct ImageParams {
};
@group(1) @binding(2) var<uniform> img_params: ImageParams;
// Draw-order depth bias (see wire.wgsl).
const DRAW_ORDER_BIAS: f32 = 0.001;
// ── Vertex stage ──────────────────────────────────────────────────────────────
struct VertIn {
@location(0) pos: vec3<f32>,
@@ -57,8 +54,7 @@ fn vs_main(in: VertIn) -> VertOut {
let rel = (in.pos + in.translation - u.eye_high)
+ (in.pos_low + in.translation_low - u.eye_low);
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
out.clip_pos.z = out.clip_pos.z
- (img_params.draw_depth + in.draw_depth) * DRAW_ORDER_BIAS * out.clip_pos.w;
out.clip_pos = apply_draw_order(out.clip_pos, img_params.draw_depth + in.draw_depth);
out.uv = in.uv;
return out;
}
+1 -4
View File
@@ -26,9 +26,6 @@ struct Uniforms {
@group(1) @binding(0) var atlas_tex: texture_2d<f32>;
@group(1) @binding(1) var atlas_samp: sampler;
// Draw-order depth bias (see wire.wgsl / image.wgsl).
const DRAW_ORDER_BIAS: f32 = 0.001;
// ── Vertex stage ──────────────────────────────────────────────────────────────
struct VertIn {
@location(0) pos: vec3<f32>,
@@ -50,7 +47,7 @@ fn vs_main(in: VertIn) -> VertOut {
// Double-single relative-to-eye, then rotation-only projection.
let rel = (in.pos - u.eye_high) + (in.pos_low - u.eye_low);
out.clip_pos = u.view_rot * vec4<f32>(rel, 1.0);
out.clip_pos.z = out.clip_pos.z - in.draw_depth * DRAW_ORDER_BIAS * out.clip_pos.w;
out.clip_pos = apply_draw_order(out.clip_pos, in.draw_depth);
out.uv = in.uv;
out.color = in.color;
return out;
+2 -2
View File
@@ -106,10 +106,10 @@ struct VOut {
let hi = h.plane_origin_high.xyz + v.translation - u.eye_high;
let lo = local_world + h.plane_origin_low.xyz + v.translation_low - u.eye_low;
o.clip = u.view_rot * vec4<f32>(hi + lo, 1.0);
// Draw-order bias (see wire.wgsl): the mask erases what draws BELOW its
// Draw-order bias (see draw_order.wgsl): the mask erases what draws BELOW its
// entity and loses to what draws above — including its own frame wire,
// which rides a +half-rank override.
o.clip.z = o.clip.z - (h.draw_depth + v.draw_depth) * 0.001 * o.clip.w;
o.clip = apply_draw_order(o.clip, h.draw_depth + v.draw_depth);
o.xz = vec2<f32>(v.pos.x, v.pos.y);
return o;
}
+2 -7
View File
@@ -67,11 +67,6 @@ struct InstanceIn {
@location(12) marker_normal_scale: vec4<f32>,
}
// Draw-order depth bias: shifts clip-space z so 2D entities of different
// types order against each other through the shared LessEqual depth test.
// draw_depth is signed (-1,1): front → positive → smaller z → drawn on top;
// 0.0 = neutral (real depth). Depth32Float gives ample precision.
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
@@ -199,7 +194,7 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, instance:
let pos_rel = mix(rel_a, rel_b, which_end);
let world_pos = pos_rel + perp_world * (eff_hw * side);
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
clip_pos.z = clip_pos.z - in.misc.x * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, in.misc.x);
final_clip = clip_pos;
out_dist = mix(in.dists.x, in.dists.y, which_end);
@@ -233,7 +228,7 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, instance:
let offset_px = perp * hw * side + dir * hw * ext;
let ndc_offset = offset_px / (u.viewport_size * 0.5);
var clip_pos_out = clip_pos + vec4<f32>(ndc_offset * clip_pos.w, 0.0, 0.0);
clip_pos_out.z = clip_pos_out.z - in.misc.x * DRAW_ORDER_BIAS * clip_pos_out.w;
clip_pos_out = apply_draw_order(clip_pos_out, in.misc.x);
final_clip = clip_pos_out;
out_dist = mix(in.dists.x, in.dists.y, which_end) + ext * hw * u.world_per_pixel;
+2 -3
View File
@@ -53,7 +53,6 @@ struct InstanceIn {
@location(7) taper_ratio: vec2<f32>,
}
const DRAW_ORDER_BIAS: f32 = 0.001;
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
@@ -172,7 +171,7 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, c: WireCon
let pos_rel = mix(rel_a, rel_b, which_end);
let world_pos = pos_rel + perp_world * (eff_hw * side);
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
clip_pos.z = clip_pos.z - c.draw_depth * DRAW_ORDER_BIAS * clip_pos.w;
clip_pos = apply_draw_order(clip_pos, c.draw_depth);
final_clip = clip_pos;
out_dist = mix(in.distance_a, in.distance_b, which_end);
@@ -206,7 +205,7 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, c: WireCon
let offset_px = perp * hw * side + dir * hw * ext;
let ndc_offset = offset_px / (u.viewport_size * 0.5);
var clip_pos_out = clip_pos + vec4<f32>(ndc_offset * clip_pos.w, 0.0, 0.0);
clip_pos_out.z = clip_pos_out.z - c.draw_depth * DRAW_ORDER_BIAS * clip_pos_out.w;
clip_pos_out = apply_draw_order(clip_pos_out, c.draw_depth);
final_clip = clip_pos_out;
out_dist = mix(in.distance_a, in.distance_b, which_end) + ext * hw * u.world_per_pixel;