anvilkit-render 0.1.0

Cross-platform rendering system built on wgpu and winit for AnvilKit game engine
Documentation
// Particle point-sprite shader

struct SceneUniform {
    view_proj: mat4x4<f32>,
};

@group(0) @binding(0)
var<uniform> scene: SceneUniform;

struct VertexInput {
    @location(0) position: vec3<f32>,
    @location(1) color: vec4<f32>,
    @location(2) size: f32,
};

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) color: vec4<f32>,
    @location(1) uv: vec2<f32>,
};

// Expand each particle into a camera-facing quad via vertex_index
// Each particle is drawn as 6 vertices (2 triangles)
fn get_corner(vid: u32) -> vec2<f32> {
    let idx = vid % 6u;
    // Triangle 1: TL, BR, TR  Triangle 2: TL, BL, BR
    // 0: (-0.5, -0.5)  1: (0.5, -0.5)  2: (0.5, 0.5)
    // 3: (-0.5, -0.5)  4: (0.5, 0.5)   5: (-0.5, 0.5)
    var x: f32 = -0.5;
    var y: f32 = -0.5;
    if idx == 1u || idx == 2u || idx == 4u {
        x = 0.5;
    }
    if idx == 2u || idx == 4u || idx == 5u {
        y = 0.5;
    }
    return vec2<f32>(x, y);
}

@vertex
fn vs_main(in: VertexInput, @builtin(vertex_index) vid: u32) -> VertexOutput {
    let corner = get_corner(vid);

    var out: VertexOutput;
    // Billboard: offset in clip space after projection
    let clip = scene.view_proj * vec4<f32>(in.position, 1.0);
    let offset = vec2<f32>(corner.x * in.size, corner.y * in.size);
    out.clip_position = vec4<f32>(clip.xy + offset * clip.w, clip.z, clip.w);
    out.color = in.color;
    out.uv = corner + vec2<f32>(0.5, 0.5);
    return out;
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    // Soft circle: distance from center
    let dist = length(in.uv - vec2<f32>(0.5, 0.5)) * 2.0;
    let alpha = 1.0 - smoothstep(0.8, 1.0, dist);
    return vec4<f32>(in.color.rgb, in.color.a * alpha);
}