Production-oriented GPU trail rendering for Bevy.
bevy_trail is an emitter-driven trail system designed for dynamic gameplay effects. It uses fixed-capacity ring buffers, storage-buffer uploads, and shader-side ribbon expansion to keep CPU overhead predictable while supporting high trail update rates.
- Stream-friendly GPU data path for frequently changing trails
- Clear ECS integration with emitter/config components
- Shader-side orientation and procedural styling hooks
- Practical baseline for extending toward segment joins/caps and advanced transparency
-
TrailPluginintegration for setup and runtime systems - Emitter-based workflow with
TrailEmitter+TrailEmitterConfig - Fixed-capacity ring storage (
head,len,capacity) per trail - Sampling controls: minimum dt, maximum dt, distance threshold
- Lifetime-based culling of stale points
- Per-point payload: position, velocity, width, color, spawn time, cumulative length
- GPU storage-buffer upload path for trail points
- Capacity-keyed strip mesh cache
- Shader-side ribbon expansion from ring-buffer data
- Billboard orientation from view direction and motion, with tangent fallbacks
- Right-vector continuity stabilization to reduce curve frame flips
- Width taper controls (
base_width,taper_factor) - Metadata-driven alpha compositing API (
AlphaMode) - Material blend selection from metadata at runtime
- Visual and smoke examples
- Stress example for many emitters (
trail_stress)
- Join styles (miter, bevel, round)
- Cap styles (butt, square, round)
- Segment-instanced rendering path (optional alternative to strip)
- Texture support with UV generation and scrolling controls
- More robust transparent self-overlap strategy
- Depth-fade intersection support against opaque geometry
- Pipeline specialization keys for transparent/depth/HDR variants
- Public antialias/falloff quality controls
- Curve-based authoring for width/color over normalized trail age or length
- Visual regression test scenes and benchmark harness
- Entities with
TrailEmitterare initialized withTrailstorage, material, and GPU buffer. - In fixed update, emitter transforms are sampled into trail points.
- Dirty trails pack point data and upload to the storage buffer.
- A cached strip mesh is rendered using a material that reads the point ring from GPU memory.
- Vertex shader expands strip vertices into camera-facing trail ribbon geometry.
src/plugin.rs: plugin wiring and emitter sampling systemssrc/components.rs: trail data model and sampling/culling logicsrc/render.rs: material, mesh cache, and GPU upload pipelineassets/shaders/trail/trail_common.wgsl: ring read helpersassets/shaders/trail/trail_ring.wgsl: vertex expansion and fragment shading
use bevy::prelude::*;
use bevy_trail::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(TrailPlugin)
.run();
}See examples/trail_visual.rs for a scene setup and examples/trail_stress.rs for load testing.
cargo run --example trail_visual
cargo run --example trail_smoke
cargo run --example trail_stress- Ring-buffer storage keeps memory bounded per emitter.
- Storage-buffer uploads avoid CPU-side mesh rebuilds per point.
- The current strip path is efficient, while higher-fidelity corner handling (joins/caps) is planned as an opt-in quality tier.
Dual licensed under MIT OR Apache-2.0.