forked from 1b-agent/opencadstudio-upstream
fix(render): miter the joints of wide polyline bands
Each band segment was a rectangle ending square at its vertex, so the outer corner of every joint showed a notch. Every segment end now carries the tangent of half its turn, and the shader slides that end's corners onto the joint's bisector so neighbours meet in a miter. Turns sharper than the limit keep butt ends. Constant-width runs inside a polyline split around its arcs no longer count as tapered, which had kept them unmitred. Fixes #1565 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
4cfcc9dc38
commit
d6dfd0d46d
6 files changed
+161
-23
No files matched your search
@@ -46,6 +46,8 @@ struct VertexIn {
|
||||
|
||||
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
|
||||
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
|
||||
// Must match `MITER_LIMIT` in wire_gpu.rs.
|
||||
const MITER_LIMIT: f32 = 8.0;
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@@ -161,13 +163,17 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
|
||||
}
|
||||
perp_world = normalize(perp_world);
|
||||
|
||||
// A constant-width band slides each corner along the segment onto
|
||||
// its joint's bisector (miter), so neighbours meet without a notch.
|
||||
let miter = select(in.taper_ratio, vec2<f32>(0.0), is_tapered) * MITER_LIMIT;
|
||||
let along = mix(miter.x, miter.y, which_end) * eff_hw * side;
|
||||
let pos_rel = mix(rel_a, rel_b, which_end);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side) + world_dir * along;
|
||||
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
|
||||
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);
|
||||
out_dist = mix(in.distances.x, in.distances.y, which_end) + along * (in.distances.y - in.distances.x) / max(world_len, 1e-6);
|
||||
out_cap = vec2<f32>(which_end * world_len, eff_hw * side);
|
||||
out_cap_ends = vec3<f32>(world_len, world_hw_a, world_hw_b);
|
||||
} else {
|
||||
|
||||
@@ -70,6 +70,8 @@ struct VertexIn {
|
||||
|
||||
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
|
||||
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
|
||||
// Must match `MITER_LIMIT` in wire_gpu.rs.
|
||||
const MITER_LIMIT: f32 = 8.0;
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@@ -144,7 +146,7 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
|
||||
let seg_pos_b = vec3<f32>(seg.pos_b_x, seg.pos_b_y, seg.pos_b_z);
|
||||
let seg_pos_b_low = vec3<f32>(seg.pos_b_low_x, seg.pos_b_low_y, seg.pos_b_low_z);
|
||||
let seg_distances = vec2<f32>(seg.distance_a, seg.distance_b);
|
||||
let seg_taper_ratio = unpack2x16unorm(seg.taper_ratio);
|
||||
let seg_taper_ratio = unpack2x16snorm(seg.taper_ratio);
|
||||
let which_end_arr = array<f32, 6>(0.0, 1.0, 1.0, 0.0, 1.0, 0.0);
|
||||
let side_arr = array<f32, 6>(-1.0, -1.0, 1.0, -1.0, 1.0, 1.0);
|
||||
let which_end = which_end_arr[corner];
|
||||
@@ -192,13 +194,17 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32, in: VertexIn) -> VertexOut
|
||||
}
|
||||
perp_world = normalize(perp_world);
|
||||
|
||||
// A constant-width band slides each corner along the segment onto
|
||||
// its joint's bisector (miter), so neighbours meet without a notch.
|
||||
let miter = select(seg_taper_ratio, vec2<f32>(0.0), is_tapered) * MITER_LIMIT;
|
||||
let along = mix(miter.x, miter.y, which_end) * eff_hw * side;
|
||||
let pos_rel = mix(rel_a, rel_b, which_end);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side) + world_dir * along;
|
||||
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
|
||||
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);
|
||||
out_dist = mix(seg_distances.x, seg_distances.y, which_end) + along * (seg_distances.y - seg_distances.x) / max(world_len, 1e-6);
|
||||
out_cap = vec2<f32>(which_end * world_len, eff_hw * side);
|
||||
out_cap_ends = vec3<f32>(world_len, world_hw_a, world_hw_b);
|
||||
} else {
|
||||
|
||||
@@ -69,6 +69,8 @@ struct InstanceIn {
|
||||
|
||||
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
|
||||
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
|
||||
// Must match `MITER_LIMIT` in wire_gpu.rs.
|
||||
const MITER_LIMIT: f32 = 8.0;
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@@ -191,13 +193,17 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, instance:
|
||||
}
|
||||
perp_world = normalize(perp_world);
|
||||
|
||||
// A constant-width band slides each corner along the segment onto
|
||||
// its joint's bisector (miter), so neighbours meet without a notch.
|
||||
let miter = vec2<f32>(in.marker_origin_high.w, in.marker_origin_low.w) * MITER_LIMIT;
|
||||
let along = mix(miter.x, miter.y, which_end) * eff_hw * side;
|
||||
let pos_rel = mix(rel_a, rel_b, which_end);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side) + world_dir * along;
|
||||
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
|
||||
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);
|
||||
out_dist = mix(in.dists.x, in.dists.y, which_end) + along * (in.dists.y - in.dists.x) / max(world_len, 1e-6);
|
||||
out_cap = vec2<f32>(which_end * world_len, eff_hw * side);
|
||||
out_cap_ends = vec3<f32>(world_len, world_hw_a, world_hw_b);
|
||||
} else {
|
||||
|
||||
@@ -55,6 +55,8 @@ struct InstanceIn {
|
||||
|
||||
const MODEL_LINEWEIGHT_BOOST: f32 = 2.0;
|
||||
const MODEL_LINEWEIGHT_MAX_PX: f32 = 10.0;
|
||||
// Must match `MITER_LIMIT` in wire_gpu.rs.
|
||||
const MITER_LIMIT: f32 = 8.0;
|
||||
|
||||
struct VertexOut {
|
||||
@builtin(position) clip_pos: vec4<f32>,
|
||||
@@ -168,13 +170,17 @@ fn marker_relative(position_high: vec3<f32>, position_low: vec3<f32>, c: WireCon
|
||||
}
|
||||
perp_world = normalize(perp_world);
|
||||
|
||||
// A constant-width band slides each corner along the segment onto
|
||||
// its joint's bisector (miter), so neighbours meet without a notch.
|
||||
let miter = select(in.taper_ratio, vec2<f32>(0.0), is_tapered) * MITER_LIMIT;
|
||||
let along = mix(miter.x, miter.y, which_end) * eff_hw * side;
|
||||
let pos_rel = mix(rel_a, rel_b, which_end);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side);
|
||||
let world_pos = pos_rel + perp_world * (eff_hw * side) + world_dir * along;
|
||||
var clip_pos = u.view_rot * vec4<f32>(world_pos, 1.0);
|
||||
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);
|
||||
out_dist = mix(in.distance_a, in.distance_b, which_end) + along * (in.distance_b - in.distance_a) / max(world_len, 1e-6);
|
||||
out_cap = vec2<f32>(which_end * world_len, eff_hw * side);
|
||||
out_cap_ends = vec3<f32>(world_len, world_hw_a, world_hw_b);
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user