Replace Chebyshev distance with a rounded box SDF for the cursor avoidance shape. Eliminates diagonal artifacts where the sharp corners of a pure square distance field intersected the ring geometry.
76 lines
2.4 KiB
WebGPU Shading Language
76 lines
2.4 KiB
WebGPU Shading Language
struct Uniforms {
|
|
screen_size: vec2f,
|
|
cursor_pos: vec2f,
|
|
// Outer rounded rect: inset from screen edge
|
|
outer_inset: f32,
|
|
outer_corner_radius: f32,
|
|
// Inner rounded rect: inset further by ring_width
|
|
ring_width: f32,
|
|
inner_corner_radius: f32,
|
|
// Glow
|
|
glow_spread: f32,
|
|
// Cursor avoidance
|
|
cursor_avoid_radius: f32,
|
|
cursor_avoid_falloff: f32,
|
|
// Color temperature (linear RGB)
|
|
_pad: f32,
|
|
color: vec3f,
|
|
_pad2: f32,
|
|
}
|
|
|
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
|
|
@vertex
|
|
fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
|
|
let x = f32(i32(i) / 2) * 4.0 - 1.0;
|
|
let y = f32(i32(i) % 2) * 4.0 - 1.0;
|
|
return vec4f(x, y, 0.0, 1.0);
|
|
}
|
|
|
|
// Rounded rectangle SDF (Inigo Quilez).
|
|
fn rounded_rect_sdf(p: vec2f, h: vec2f, r: f32) -> f32 {
|
|
let q = abs(p) - h + vec2f(r);
|
|
return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - r;
|
|
}
|
|
|
|
@fragment
|
|
fn fs_main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
|
|
let center = u.screen_size / 2.0;
|
|
let p = pos.xy - center;
|
|
|
|
// Outer rounded rect
|
|
let outer_half = center - vec2f(u.outer_inset);
|
|
let sd_outer = rounded_rect_sdf(p, outer_half, u.outer_corner_radius);
|
|
|
|
// Inner rounded rect
|
|
let inner_half = outer_half - vec2f(u.ring_width);
|
|
let sd_inner = rounded_rect_sdf(p, inner_half, u.inner_corner_radius);
|
|
|
|
// Ring: inside outer AND outside inner = solid at full brightness
|
|
var alpha: f32;
|
|
if sd_outer <= 0.0 && sd_inner >= 0.0 {
|
|
alpha = 1.0;
|
|
} else if sd_outer > 0.0 {
|
|
// Gaussian glow fading outward
|
|
let t = sd_outer / u.glow_spread;
|
|
alpha = exp(-3.0 * t * t);
|
|
} else {
|
|
// Gaussian glow fading inward
|
|
let t = -sd_inner / u.glow_spread;
|
|
alpha = exp(-3.0 * t * t);
|
|
}
|
|
|
|
// Cursor avoidance — rounded square (box SDF with corner rounding)
|
|
let cursor_half = vec2f(u.cursor_avoid_radius);
|
|
let cursor_corner = u.cursor_avoid_radius * 0.3; // 30% rounding smooths the diagonals
|
|
let cursor_sd = rounded_rect_sdf(pos.xy - u.cursor_pos, cursor_half, cursor_corner);
|
|
if cursor_sd < u.cursor_avoid_falloff {
|
|
let t_avoid = clamp(cursor_sd / u.cursor_avoid_falloff, 0.0, 1.0);
|
|
alpha *= t_avoid * t_avoid * (3.0 - 2.0 * t_avoid);
|
|
}
|
|
|
|
// Premultiplied color output
|
|
let rgb = u.color * alpha;
|
|
return vec4f(rgb, alpha);
|
|
}
|