diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2026-08-25 00:32:16 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2026-08-25 00:32:16 -0700 |
| commit | a779011b9048cdda04887c77e20ee8936f332a7a (patch) | |
| tree | 6a771ff692d1717967755cc56e4534a582dd117a /src/shader | |
| parent | 9cb48c504ddb3882f39e2b17048f0593316a95ce (diff) | |
vfx pipeline
Diffstat (limited to 'src/shader')
| -rw-r--r-- | src/shader/instance.wgsl | 6 | ||||
| -rw-r--r-- | src/shader/particle.wgsl | 11 | ||||
| -rw-r--r-- | src/shader/vfx_line.wgsl | 76 |
3 files changed, 85 insertions, 8 deletions
diff --git a/src/shader/instance.wgsl b/src/shader/instance.wgsl index fb1e0b1..a549801 100644 --- a/src/shader/instance.wgsl +++ b/src/shader/instance.wgsl @@ -17,8 +17,8 @@ struct Instance { @group(0) @binding(3) var<storage, read> cells: array<u32>; struct VertexOutput { - @builtin(position) clip_position: vec4<f32>, - @location(0) world: vec2<f32>, + @builtin(position) clip_position: vec4f, + @location(0) world: vec2f, @location(1) @interpolate(flat) instance: u32, }; @@ -46,7 +46,7 @@ fn vs_main( } @fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { +fn fs_main(in: VertexOutput) -> @location(0) vec4f { let instance = instances[in.instance]; let d = in.world - instance.centre; diff --git a/src/shader/particle.wgsl b/src/shader/particle.wgsl index 3dd61a9..227468b 100644 --- a/src/shader/particle.wgsl +++ b/src/shader/particle.wgsl @@ -14,8 +14,8 @@ struct Particle { @group(0) @binding(2) var<storage, read> particles: array<Particle>; struct VertexOutput { - @builtin(position) clip_position: vec4<f32>, - @location(0) world: vec2<f32>, + @builtin(position) clip_position: vec4f, + @location(0) world: vec2f, @location(1) @interpolate(flat) instance: u32, @location(2) @interpolate(flat) material: u32, @location(3) @interpolate(flat) life: f32, @@ -29,7 +29,7 @@ fn vs_main( let particle = particles[n]; // (0,0),(1,0),(0,1),(1,1) - let corner = vec2<f32>(f32(i & 1u), f32((i >> 1u) & 1u)); + let corner = vec2f(f32(i & 1u), f32((i >> 1u) & 1u)); let world = particle.position + corner; var out: VertexOutput; @@ -43,9 +43,10 @@ fn vs_main( } @fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { +fn fs_main(in: VertexOutput) -> @location(0) vec4f { let particle = particles[in.instance]; // TODO can pack more in here and shift let c = palette[in.material]; - return vec4<f32>(c.r, c.g, c.b, c.a * smoothstep(0.0, 1, in.life)); + // if life is less than 1, smoothly reduce alpha to 0 + return vec4f(c.r, c.g, c.b, c.a * smoothstep(0.0, 1, in.life)); } diff --git a/src/shader/vfx_line.wgsl b/src/shader/vfx_line.wgsl new file mode 100644 index 0000000..bef7645 --- /dev/null +++ b/src/shader/vfx_line.wgsl @@ -0,0 +1,76 @@ +struct Camera { + scale: vec2f, + centre: vec2f, +}; + +struct MaterialDef { + color: vec4f, + // the length of the path segment for t + length: f32, +}; + +struct VfxLine { + a: vec2f, + b: vec2f, + width: f32, + material: u32, + alive_for: f32, + lifetime: f32, +} + +@group(0) @binding(0) var<uniform> camera: Camera; +@group(0) @binding(1) var<storage, read> materials: array<MaterialDef>; +@group(0) @binding(2) var<storage, read> vfx_lines: array<VfxLine>; + +struct VertexOutput { + @builtin(position) clip_position: vec4f, + @location(0) @interpolate(flat) color: vec4f, + // the length of the path segment for t + @location(1) @interpolate(flat) length: f32, + @location(2) @interpolate(flat) cur_centre: f32, + @location(3) dist: f32, +}; + +@vertex +fn vs_main( + @builtin(vertex_index) i: u32, + @builtin(instance_index) n: u32, +) -> VertexOutput { + let vfx_line = vfx_lines[n]; + + let d = vfx_line.b - vfx_line.a; + // (-y, x) is a 90deg ccw rotation + let p = normalize(vec2f(-d.y, d.x)) * (vfx_line.width * 0.5); + // 0=a,1=b + let cv = f32(i & 1u); + // direction to offset the orthogonal width + let co = f32(i >> 1u) * 2.0 - 1.0; + // select a/b, add offset + let world = mix(vfx_line.a, vfx_line.b, cv) + p * co; + var out: VertexOutput; + out.clip_position = vec4f((world - camera.centre) * camera.scale, 0.0, 1.0); + + // material + let material = materials[vfx_line.material]; + out.color = material.color; + out.length = material.length; + + // computed + let l = length(d); + out.cur_centre = (l + material.length) * (vfx_line.alive_for / vfx_line.lifetime) - (material.length / 2); + + // interpolated + out.dist = cv * l; + + return out; +} + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4f { + // distance on line of the centre of the current (w.r.t. time) line segment + // can do this in vertex + // our distance along the line vs the current centre + let dist_from_centre = abs(in.dist - in.cur_centre); + let c = in.color; + return vec4f(c.r, c.g, c.b, c.a * (1 - smoothstep(0.0, in.length / 2, dist_from_centre))); +} |
