From 74665d696d2719fc5397614b206df9d1aa7ec93c Mon Sep 17 00:00:00 2001 From: Daniel <101683475+Koranir@users.noreply.github.com> Date: Thu, 29 May 2025 22:16:33 +1000 Subject: [PATCH] use single sdf for all corners --- wgpu/src/shader/quad.wgsl | 32 +++------------- wgpu/src/shader/quad/gradient.wgsl | 43 +++++---------------- wgpu/src/shader/quad/solid.wgsl | 60 +++++++++--------------------- 3 files changed, 33 insertions(+), 102 deletions(-) diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index b213c8cf..f8258a4e 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -5,31 +5,9 @@ struct Globals { @group(0) @binding(0) var globals: Globals; -fn distance_alg( - frag_coord: vec2, - position: vec2, - size: vec2, - radius: f32 -) -> f32 { - var inner_half_size: vec2 = (size - vec2(radius, radius) * 2.0) / 2.0; - var top_left: vec2 = position + vec2(radius, radius); - return rounded_box_sdf(frag_coord - top_left - inner_half_size, inner_half_size, 0.0); -} - -// Given a vector from a point to the center of a rounded rectangle of the given `size` and -// border `radius`, determines the point's distance from the nearest edge of the rounded rectangle -fn rounded_box_sdf(to_center: vec2, size: vec2, radius: f32) -> f32 { - return length(max(abs(to_center) - size + vec2(radius, radius), vec2(0.0, 0.0))) - radius; -} - -// Based on the fragment position and the center of the quad, select one of the 4 radii. -// Order matches CSS border radius attribute: -// radii.x = top-left, radii.y = top-right, radii.z = bottom-right, radii.w = bottom-left -fn select_border_radius(radii: vec4, position: vec2, center: vec2) -> f32 { - var rx = radii.x; - var ry = radii.y; - rx = select(radii.x, radii.y, position.x > center.x); - ry = select(radii.w, radii.z, position.x > center.x); - rx = select(rx, ry, position.y > center.y); - return rx; +fn rounded_box_sdf(p: vec2, size: vec2, corners: vec4) -> f32 { + var box_half = select(corners.yz, corners.xw, p.x > 0.0); + var corner = select(box_half.y, box_half.x, p.y > 0.0); + var q = abs(p) - size + corner; + return min(max(q.x, q.y), 0.0) + length(max(q, vec2(0.0))) - corner; } diff --git a/wgpu/src/shader/quad/gradient.wgsl b/wgpu/src/shader/quad/gradient.wgsl index a1b4b107..b80b3f7f 100644 --- a/wgpu/src/shader/quad/gradient.wgsl +++ b/wgpu/src/shader/quad/gradient.wgsl @@ -157,42 +157,19 @@ fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4 { let pos = input.position_and_scale.xy; let scale = input.position_and_scale.zw; - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (pos + scale * 0.5).xy - ); + var dist: f32 = rounded_box_sdf( + -(input.position.xy - pos - scale / 2.0) * 2.0, + scale, + input.border_radius * 2.0 + ) / 2.0; if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - pos + vec2(input.border_width, input.border_width), - scale - vec2(input.border_width * 2.0, input.border_width * 2.0), - internal_border + mixed_color = mix( + mixed_color, + input.border_color, + clamp(0.5 + dist + input.border_width, 0.0, 1.0) ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(mixed_color, input.border_color, border_mix); } - var dist: f32 = distance_alg( - input.position.xy, - pos, - scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist); - - return mixed_color * radius_alpha; + return mixed_color * clamp(0.5-dist, 0.0, 1.0); } diff --git a/wgpu/src/shader/quad/solid.wgsl b/wgpu/src/shader/quad/solid.wgsl index f4c39f3d..5578ade3 100644 --- a/wgpu/src/shader/quad/solid.wgsl +++ b/wgpu/src/shader/quad/solid.wgsl @@ -75,57 +75,33 @@ fn solid_fs_main( ) -> @location(0) vec4 { var mixed_color: vec4 = input.color; - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (input.pos + input.scale * 0.5).xy - ); + var dist = rounded_box_sdf( + -(input.position.xy - input.pos - input.scale * 0.5) * 2.0, + input.scale, + input.border_radius * 2.0 + ) / 2.0; if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - input.pos + vec2(input.border_width, input.border_width), - input.scale - vec2(input.border_width * 2.0, input.border_width * 2.0), - internal_border + mixed_color = mix( + input.color, + input.border_color, + clamp(0.5 + dist + input.border_width, 0.0, 1.0) ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(input.color, input.border_color, border_mix); } - var dist: f32 = distance_alg( - vec2(input.position.x, input.position.y), - input.pos, - input.scale, - border_radius - ); + var quad_alpha: f32 = clamp(0.5-dist, 0.0, 1.0); - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist - ); - - let quad_color = mixed_color * radius_alpha; + let quad_color = mixed_color * quad_alpha; if input.shadow_color.a > 0.0 { - let shadow_radius = select_border_radius( - input.border_radius, - input.position.xy - input.shadow_offset, - (input.pos + input.scale * 0.5).xy - ); + var shadow_dist: f32 = rounded_box_sdf( + -(input.position.xy - input.pos - input.shadow_offset - input.scale/2.0) * 2.0, + input.scale, + input.border_radius * 2.0 + ) / 2.0; + let shadow_alpha = 1.0 - smoothstep(-input.shadow_blur_radius, input.shadow_blur_radius, max(shadow_dist, 0.0)); - let shadow_distance = max(rounded_box_sdf(input.position.xy - input.pos - input.shadow_offset - (input.scale / 2.0), input.scale / 2.0, shadow_radius), 0.); - let shadow_alpha = 1.0 - smoothstep(-input.shadow_blur_radius, input.shadow_blur_radius, shadow_distance); - - return mix(quad_color, input.shadow_color, (1.0 - radius_alpha) * shadow_alpha); + return mix(quad_color, input.shadow_color, (1.0 - quad_alpha) * shadow_alpha); } else { return quad_color; }