Skip to content

scenix v1.7.0 — Particles

Choose a tag to compare

@github-actions github-actions released this 18 Oct 10:11
· 4 commits to main since this release
26bd38c

Scenix v1.7.0 — Particles

Scenix 1.7.0 adds the optional scenix-particles crate: deterministic CPU
particle systems with a no_std-capable core, plus an instanced billboard GPU
draw path and an optional GPU compute simulation in scenix-renderer.
Everything is additive and feature-gated; the default facade build behaves
exactly like v1.6.0.

Highlights

  • scenix-particles is a standalone, no_std-capable CPU crate (std/serde
    features): ParticleEmitter builder, pools up to PARTICLE_POOL_LIMIT
    (262,144), burst + rate spawning, per-particle Particle records
    (position, velocity, age, lifetime, size, rotation, flipbook
    frame), and one reusable ParticleRenderBatch per update.
  • A module vocabulary composes behavior on the emitter: Gravity, Drag,
    ColorOverLifetime (deterministic ColorCurve keys with sRGB/linear aware
    blends), SizeOverLifetime, SpinOverLife, and ConfineBox, all behind
    the ParticleModifier trait. EmissionShape covers points, spheres,
    hemispheres, discs, cones, and boxes with a toward shortcut.
  • Simulation is seeded, so identical configs replay identically across
    resets and hosts — verified by an integration test that re-runs the same
    scenario twice.
  • scenix-texture::FlipbookGrid is the pure frame-index → UV math shared by
    particles and sprites (uniform columns × rows sheets, top-left origin,
    clamp-pad on the last frame). The particle side mirrors it with
    FlipbookConfig for frame rate and looping.
  • scenix-mesh::quad_geometry(width, height) builds the CCW +Z billboard
    quad with scenix's plane UV convention (v = 1 at the bottom), usable for
    sprite and expanded-fallback draws.
  • scenix-material::ParticleMaterial carries tint, optional sprite texture,
    optional flipbook, soft-edge fade, and an Additive VS Alpha blend enum.
    Its FeatureBits add FEATURE_SOFT_PARTICLES (1 << 20) and
    FEATURE_FLIPBOOK (1 << 21), and ShaderKind::Particles selects the
    billboard pipeline key.
  • scenix-renderer (behind renderer + particles) owns a GPU particle
    registry: register_particles installs a slot, update_particles uploads
    one CPU batch per frame into an instanced buffer, resolve hooks into
    registered textures, and encode_frame draws camera-facing billboards from
    a 64-byte instance record (center/size, premultiplied color, UV rect,
    rotation). Additive and alpha pipelines share the depth-test-on /
    depth-write-off contract, so particles layer over the lit scene without
    sorting.
  • Optional GPU compute: register_particle_compute seeds a 64-byte-per-slot
    GPU pool from a CPU system snapshot; simulate_particles_compute then
    integrate gravity + drag with size/color fades and dispatches a
    deterministic ring-window respawn pass (single invocation, no atomics).
    read_particle_pool / read_particle_ring copy results back to the host
    for editors, debugging, and tests.
  • CPU updates always win: calling update_particles converts a slot back to
    the CPU-driven draw path.
  • scenix-wasm documents the browser fallback plan: WebGPU gets the full
    draw + compute path, WebGL 2 gets instanced billboards with CPU
    simulation, and WebGL 1 expands billboards to real quad geometry.
  • scenix-shader math gains a public scenix_math::float shim module
    (sqrt/sin/cos/tan, inverse trig, atan2, cbrt) so libm-only EfFn builds
    keep the same APIs as std builds.

Small Example

use scenix::{
    ColorOverLifetime, ColorCurve, Drag, EmissionShape, FlipbookConfig, Gravity, ParticleEmitter,
    ParticleMaterial, ParticleSystem, Vec3, SizeOverLifetime,
};

let emitter = ParticleEmitter::new()
    .with_rate(240.0)
    .with_lifetime(0.9, 1.6)
    .with_size(0.2)
    .with_speed(4.0, 7.0)
    .at(Vec3::new(0.0, 0.0, 0.0))
    .toward(Vec3::new(0.0, 1.0, 0.0))
    .with_shape(EmissionShape::Cone { radius: 0.15, height: 0.35 })
    .with_modifier(Gravity::new(Vec3::new(0.0, -12.0, 0.0)))
    .with_modifier(Drag::new(0.15))
    .with_modifier(ColorOverLifetime::new(ColorCurve::from_to(
        [1.0, 0.85, 0.35, 1.0],
        [0.9, 0.15, 0.0, 0.0],
    )))
    .with_modifier(SizeOverLifetime::from_to(1.15, 0.05));

let mut system = ParticleSystem::new(emitter, 1_024, 2021018); // deterministic seed
system.set_flipbook(Some(FlipbookConfig::full(4, 4, 24.0)));
system.update(1.0 / 60.0); // advances the CPU sim and returns the render batch

// GPU: registration is one call; `Renderer::update_particles` uploads the
// batch as instanced billboards (renderer + particles features).
let material = ParticleMaterial::new()
    .with_color(scenix::Color::from_rgb(1.0, 0.9, 0.6));

Feature Flags

  • particles: enables scenix-particles through the facade with curated
    re-exports (emitters, modifiers, curves, batches, flipbook config) plus
    the default-enabled material/texture types the draw path needs.
  • particles + renderer: the GPU billboard path and the optional compute
    simulation (register_particles, update_particles,
    register_particle_compute, simulate_particles_compute,
    read_particle_pool).
  • particles + wasm: browser fallback plan helpers
    (particle_fallback_plan) published through the facade wasm surface.
  • scenix-particles standalone: no_std-capable CPU crate (std/serde
    features).

Examples

cargo run -p scenix --example particles_basic --features particles
# GPU tail (needs a wgpu adapter; lavapipe works):
cargo run -p scenix --example particles_basic --features particles,renderer

Compatibility

  • All 19 workspace crates are version 1.7.0 and require Rust 1.98.
  • No existing enum gained variants; default features are unchanged.
  • NodeKind::Particles { system_id } joins the scene graph and reports as
    "particles" in inspector snapshots; scene YAML/JSON payloads that never
    wrote particle nodes are unaffected.
  • The GPU pool record is 64 bytes (four vec4 fields) and the draw instance
    is 64 bytes; both are re-exported as PARTICLE_POOL_STRIDE and
    PARTICLE_INSTANCE_STRIDE for direct consumers.
  • GPU-gated tests (SCENIX_RUN_GPU_TESTS=1) cover the billboard pipeline
    against a headless renderer and the compute lifecycle (integrate → expire
    → ring respawn → cursor boundary) on lavapipe-friendly software
    platforms.

Testing

  • cargo test -p scenix-particles --all-features — CPU simulation determinism,
    capacity and spawn-burst behavior, modifier composition, flipbook batches,
    and serde round trips.
  • cargo test -p scenix --test scenix_v17 --all-features — facade-level CPU
    coverage across particles, material bits, flipbook grids, billboard
    geometry, float shims, and browser fallback plans.
  • SCENIX_RUN_GPU_TESTS=1 cargo test -p scenix-renderer --test particles_gpu --features particles — wgpu pipeline + compute
    validation on software rasterizers.