berdicles 0.3.0

Expressive CPU particle system for the bevy engine.
Documentation
#define_import_path berdicle

#import bevy_pbr::mesh_functions::get_world_from_local;
#import bevy_pbr::view_transformations::{
    position_world_to_clip, 
    position_world_to_view,
    position_view_to_clip,
};

@group(1) @binding(0) var<uniform> local_to_world_x: vec4<f32>;
@group(1) @binding(1) var<uniform> local_to_world_y: vec4<f32>;
@group(1) @binding(2) var<uniform> local_to_world_z: vec4<f32>;

@group(2) @binding(0) var<uniform> color: vec4<f32>;
@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;

struct Vertex {
    @builtin(instance_index) instance_index: u32,
    @location(0) position: vec3<f32>,
#ifdef VERTEX_NORMALS
    @location(1) normal: vec3<f32>,
#endif
    @location(2) uv: vec2<f32>,
#ifdef VERTEX_UVS_B
    @location(3) uv_b: vec2<f32>,
#endif
#ifdef VERTEX_TANGENTS
    @location(4) tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
    @location(5) vertex_color: vec4<f32>,
#endif

    @location(10) id: u32,
    @location(11) lifetime: f32,
    @location(12) seed: f32,
    @location(13) fac: f32,

    @location(14) transform_x: vec4<f32>,
    @location(15) transform_y: vec4<f32>,
    @location(16) transform_z: vec4<f32>,
    @location(17) color: vec4<f32>,
};

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,

    @location(0) id: u32,
    @location(1) lifetime: f32,
    @location(2) fac: f32,
    @location(3) seed: f32,
    @location(4) color: vec4<f32>,
    @location(5) uv: vec2<f32>,
#ifdef VERTEX_NORMALS
    @location(6) normal: vec3<f32>,
#endif
#ifdef VERTEX_COLORS
    @location(7) vertex_color: vec4<f32>,
#endif
};

@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
    var out: VertexOutput;
#ifndef BILLBOARD
    let position = vec3(
        dot(vec4(vertex.position, 1.0), vertex.transform_x),
        dot(vec4(vertex.position, 1.0), vertex.transform_y),
        dot(vec4(vertex.position, 1.0), vertex.transform_z),
    );
    let world_position = vec3(
        dot(vec4(position, 1.0), local_to_world_x),
        dot(vec4(position, 1.0), local_to_world_y),
        dot(vec4(position, 1.0), local_to_world_z),
    );
    out.clip_position = position_world_to_clip(world_position);
#ifdef VERTEX_NORMALS
    // This only works if scale is uniform, otherwise an approximation.
    // todo: fix this
    let normal = vec3(
        dot(vec4(vertex.normal, 1.0), vertex.transform_x),
        dot(vec4(vertex.normal, 1.0), vertex.transform_y),
        dot(vec4(vertex.normal, 1.0), vertex.transform_z),
    );
    let world_normal = vec3(
        dot(vec4(normal, 1.0), local_to_world_x),
        dot(vec4(normal, 1.0), local_to_world_y),
        dot(vec4(normal, 1.0), local_to_world_z),
    );
    out.normal = normalize(world_normal);
#endif
#else
    let transform = vec3(vertex.transform_x.w, vertex.transform_y.w, vertex.transform_z.w);
    let world_position = vec3(
        dot(vec4(transform, 1.0), local_to_world_x),
        dot(vec4(transform, 1.0), local_to_world_y),
        dot(vec4(transform, 1.0), local_to_world_z),
    );
    let position = position_world_to_view(world_position);
    let vertex_position = vec3(
        dot(vec2(vertex.position.xy), vertex.transform_x.xy),
        dot(vec2(vertex.position.xy), vertex.transform_y.xy),
        vertex.position.z
    );
    out.clip_position = position_view_to_clip(position + vertex_position);
#ifdef VERTEX_NORMALS
    // The intension is 2d object, so don't change the normal
    out.normal = vertex.normal;
#endif
#endif
    out.id = vertex.id;
    out.lifetime = vertex.lifetime;
    out.fac = vertex.fac;
    out.seed = vertex.seed;
    out.color = vertex.color;
#ifdef VERTEX_COLORS
    out.vertex_color = vertex.vertex_color;
#endif
    out.uv = vertex.uv;
    return out;
}

@fragment
fn fragment(input: VertexOutput) -> @location(0) vec4<f32> {
    let sampled = textureSample(texture, texture_sampler, input.uv);
    return input.color * color * sampled
#ifdef VERTEX_COLORS
        * input.vertex_color
#endif
    ;
}