time_travel/assets/shaders/bezier.wgsl
2026-03-17 20:00:07 -05:00

62 lines
1.3 KiB
WebGPU Shading Language

struct Material {
p0: vec2<f32>,
c0: vec2<f32>,
c1: vec2<f32>,
p1: vec2<f32>,
width: f32,
color: vec4<f32>,
};
@group(2) @binding(0)
var<uniform> mat: Material;
fn bezier(p0: vec2<f32>, c0: vec2<f32>, c1: vec2<f32>, p1: vec2<f32>, t: f32) -> vec2<f32> {
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>) -> 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<f32>,
) -> @location(0) vec4<f32> {
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);
}