|
2 | 2 | @group(0) @binding(1) var<uniform> params: Params; |
3 | 3 |
|
4 | 4 | struct Params { |
5 | | - time: f32, |
6 | | - screenwidth: u32, |
7 | | - screenheight: u32, |
| 5 | + time: f32, |
| 6 | + screenwidth: u32, |
| 7 | + screenheight: u32, |
8 | 8 | }; |
9 | 9 |
|
10 | | -fn sdf(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 { |
11 | | - // Signed distance function (SDF) for a circle |
12 | | - // See https://iquilezles.org/articles/distfunctions2d/ |
13 | | - return length(p - c) - r; |
| 10 | +struct Particle { |
| 11 | + position: vec2<f32>, |
| 12 | + velocity: vec2<f32>, |
| 13 | + life: f32, |
14 | 14 | } |
15 | 15 |
|
16 | | -@compute @workgroup_size(16, 16, 1) |
17 | | -fn main(@builtin(global_invocation_id) globalID : vec3<u32>) { |
| 16 | +const NUM_PARTICLES: u32 = 1000u; |
| 17 | +const PARTICLE_LIFE: f32 = 9.0; |
| 18 | +const EMISSION_RATE: f32 = 300.0; |
18 | 19 |
|
19 | | - // Normalize xy coordinates |
20 | | - let xy: vec2<f32> = |
21 | | - vec2<f32>(f32(globalID.x) / f32(params.screenwidth), |
22 | | - f32(globalID.y) / f32(params.screenheight)); |
23 | | - |
24 | | - // 1-D index into the output GPU buffer |
25 | | - let idx = globalID.y * params.screenwidth + globalID.x; |
| 20 | +fn rand(n: f32) -> f32 { |
| 21 | + return fract(sin(n) * 43758.5453123); |
| 22 | +} |
26 | 23 |
|
27 | | - // Draw a circle, oscillating with time |
28 | | - let position = vec2<f32>(0.5, 0.5 + 0.1 * sin(3.0 * params.time)); |
29 | | - out[idx] = 0.3 - min(5 * abs(sdf(xy, position, 0.2)), 0.3); |
| 24 | +fn initialize_particle(id: f32, time: f32) -> Particle { |
| 25 | + let random1 = rand(id * 0.01 + time * 0.1); |
| 26 | + let random2 = rand(id * 0.02 + time * 0.1); |
| 27 | + let angle = random1 * 2.0 * 3.14159; |
| 28 | + let speed = 0.05 + random2 * 0.05; |
| 29 | + |
| 30 | + return Particle( |
| 31 | + vec2<f32>(0.5, 0.5), |
| 32 | + vec2<f32>(cos(angle) * speed, sin(angle) * speed), |
| 33 | + PARTICLE_LIFE |
| 34 | + ); |
| 35 | +} |
30 | 36 |
|
| 37 | +@compute @workgroup_size(16, 16, 1) |
| 38 | +fn main(@builtin(global_invocation_id) globalID : vec3<u32>) { |
| 39 | + let resolution = vec2<f32>(f32(params.screenwidth), f32(params.screenheight)); |
| 40 | + let uv = vec2<f32>(f32(globalID.x) / resolution.x, f32(globalID.y) / resolution.y); |
| 41 | + let idx = globalID.y * params.screenwidth + globalID.x; |
| 42 | + |
| 43 | + var color: f32 = 0.0; |
| 44 | + |
| 45 | + for (var i: f32 = 0.0; i < f32(NUM_PARTICLES); i += 1.0) { |
| 46 | + let spawn_time = i / EMISSION_RATE; |
| 47 | + let particle_age = fract((params.time - spawn_time) / PARTICLE_LIFE) * PARTICLE_LIFE; |
| 48 | + |
| 49 | + if (particle_age < PARTICLE_LIFE) { |
| 50 | + var particle = initialize_particle(i, spawn_time); |
| 51 | + particle.position += particle.velocity * particle_age; |
| 52 | + |
| 53 | + let distance = length(uv - particle.position); |
| 54 | + if (distance < 0.005) { |
| 55 | + color += 0.5 * (1.0 - particle_age / PARTICLE_LIFE); |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + out[idx] = min(color, 1.0); |
31 | 61 | } |
0 commit comments