struct Material { p0: vec2, c0: vec2, c1: vec2, p1: vec2, width: f32, color: vec4, }; @group(2) @binding(0) var mat: Material; fn bezier(p0: vec2, c0: vec2, c1: vec2, p1: vec2, t: f32) -> vec2 { let u = 1.0 - t; return u*u*u*p0 + 3.0*u*u*t*c0 + 3.0*u*t*t*c1 + t*t*t*p1; } fn distance_to_bezier(p: vec2) -> f32 { var min_d = 1e9; let steps = 32; var prev = mat.p0; for (var i = 1; i <= steps; i++) { let t = f32(i) / f32(steps); let cur = bezier(mat.p0, mat.c0, mat.c1, mat.p1, t); // distance to segment let v = cur - prev; let w = p - prev; let t_seg = clamp(dot(w, v) / dot(v, v), 0.0, 1.0); let proj = prev + t_seg * v; min_d = min(min_d, distance(p, proj)); prev = cur; } return min_d; } @fragment fn fragment( @location(0) world_pos: vec3, ) -> @location(0) vec4 { let d = distance_to_bezier(world_pos.xy); let half_w = mat.width * 0.5; let aa = fwidth(d); let alpha = smoothstep(half_w + aa, half_w - aa, d); if (alpha <= 0.001) { discard; } return vec4(mat.color.rgb, mat.color.a * alpha); }