summaryrefslogtreecommitdiff
path: root/src/shader/vfx_line.wgsl
blob: bef7645b85477b8b4df999e2fba80a15c02af9a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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)));
}