Skip to main content

PARTICLE_VERT_SRC

Constant PARTICLE_VERT_SRC 

Source
pub const PARTICLE_VERT_SRC: &str = r#"
#version 430 core

// Per-vertex (unit quad)
layout(location = 0) in vec2 v_pos;   // [-0.5, 0.5]
layout(location = 1) in vec2 v_uv;    // [0, 1]

// Particle SSBO (read-only in vertex shader)
struct Particle {
    vec3  position;
    float _pad0;
    vec3  velocity;
    float _pad1;
    vec4  color;
    float life;
    float max_life;
    float size;
    uint  engine_type;
    float seed;
    uint  flags;
    float _reserved0;
    float _reserved1;
};

layout(std430, binding = 0) readonly buffer ParticleBuffer {
    Particle particles[];
};

uniform mat4 u_view_proj;
uniform vec3 u_camera_right;
uniform vec3 u_camera_up;
uniform float u_time;

out vec2 f_uv;
out vec4 f_color;
out float f_age_frac;
out float f_emission;

void main() {
    Particle p = particles[gl_InstanceID];

    // Skip dead particles (alpha will be zero, but also move off-screen).
    if (p.life <= 0.0) {
        gl_Position = vec4(0.0, 0.0, -999.0, 1.0);
        f_color = vec4(0.0);
        f_uv = vec2(0.0);
        f_age_frac = 1.0;
        f_emission = 0.0;
        return;
    }

    float age_frac = 1.0 - clamp(p.life / p.max_life, 0.0, 1.0);

    // Size modulation over lifetime: starts at full, shrinks in last 20%.
    float size_mod = 1.0;
    if (age_frac > 0.8) {
        size_mod = 1.0 - (age_frac - 0.8) * 5.0;
    }
    float particle_size = p.size * size_mod;

    // Billboard: orient quad to face camera.
    vec3 world_pos = p.position
        + u_camera_right * v_pos.x * particle_size
        + u_camera_up    * v_pos.y * particle_size;

    gl_Position = u_view_proj * vec4(world_pos, 1.0);
    gl_Position.y = -gl_Position.y; // FBO Y inversion

    f_uv = v_uv;
    f_color = p.color;
    f_age_frac = age_frac;

    // Emission based on engine type: some engines glow more.
    float base_emission = 0.0;
    if (p.engine_type == 1u) base_emission = 0.5; // Lorenz
    if (p.engine_type == 4u) base_emission = 0.4; // Rossler
    if (p.engine_type == 7u) base_emission = 0.3; // Halvorsen
    f_emission = base_emission * (1.0 - age_frac);
}
"#;
Expand description

Vertex shader that reads particle data from SSBO and renders instanced quads.

Each particle is a camera-facing (billboard) quad. The vertex shader reads position/size/color from the SSBO via gl_InstanceID.