Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lommix/bevy_enoki

2D particle system with custom material traits. Works well in wasm webgl2 and mobile
https://github.com/lommix/bevy_enoki

2d bevy graphics particles

Last synced: 4 days ago
JSON representation

2D particle system with custom material traits. Works well in wasm webgl2 and mobile

Awesome Lists containing this project

README

        



Bevy Enoki


[![License: MIT or Apache 2.0](https://img.shields.io/badge/License-MIT%20or%20Apache2-blue.svg)](./LICENSE)
[![Crate](https://img.shields.io/crates/v/bevy_enoki.svg)](https://crates.io/crates/bevy_enoki)

Enoki - A 2D particle system for the Bevy game engine.

![animation](docs/output.gif)

## Overview

The Enoki particle system is a CPU calculate particle system, that uses GPU Instancing and works well in `wasm` and mobile.
You have access to a `Material Trait` which let's you implement your own
fragment shaders on top. Resulting in a powerful tool to build any modern VFX effect.

Additionally, spawner configuration are provided via `ron` files, which can be hot reloaded.
The default material allows not only for custom textures, but also sprite sheet animations over the particle lifetime.

## Compatibility

| bevy | bevy_enoki |
| ---: | ---------: |
| 0.15 | 0.3.3 |
| 0.14 | 0.2.2 |
| 0.13 | 0.1 |

## Editor

Enoki has a feature rich Editor.

![editor](docs/editor.jpg)

- load and save effect assets.
- watch a shader file with hot reload, your editor of choice.
- load a texture.
- play with values.

Get started by installing it via cargo
```
cargo install enoki2d_editor
```

---

## Examples

```shell
cargo run -p example --bin material
cargo run -p example --bin sprites
cargo run -p example --bin dynamic
```

## Usage

Add the `bevy_enoki` dependency to your `Cargo.toml`

```toml
bevy_enoki = "0.2.2"
```

Add the `EnokiPlugin` to your app

```rust
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(EnokiPlugin)
.run()
```

Create your first particle spawner.

```rust
use bevy_enoki::prelude::*;

fn setup(
mut cmd : Commands,
mut materials: ResMut>,
server : Res,
){
cmd.spawn(Camera2dBundle::default());

// minimal setup
// white quads with a default effect
cmd.spawn(
// the main component.
// holds a material handle.
// defaults to a simple white color quad.
// has required components
ParticleSpawner::default()
)

// bring in your own effect asset from a ron file
// (hot reload by default)
cmd.spawn((
ParticleSpawner::default(),
// the effect components holds the baseline
// effect asset.
ParticleEffectHandle(server.load("firework.particle.ron")),
));

// now with a sprite sheet animation over lifetime
let sprite_material = materials.add(
// the other args (hframes and vframes) defines how the sprite sheet is divided for animating,
// you can also just use `form_texture` for a single sprite
SpriteParticle2dMaterial::new(server.load("particle.png"), 6, 1),
);

cmd.spawn((
ParticleSpawner(sprite_material),
ParticleEffectHandle(server.load("firework.particle.ron")),
));
}
```

## Control your particles

There 4 main components you can play with. These are required by the `ParticleSpawner`
and thus added, if not provided.

- `ParticleSpawnerState`: Controls the spawner state.
- `ParticleEffectInstance`: A unique clone of the effect. Can be changed at runtime, only affects the spawner attached to. Will reload, when the asset changes.
- `ParticleEffectHandle`: A link the main effect asset.
- `ParticleStore`: Holds the particle data. You mostly won't interact with this.
- `OneShot`: A optional Tag component. That will either deactivate or delete the spawner, after first burst is done.
- `NoAutoAabb`: Opt out of auto Aabb calculation.

## Create a custom Material

Just like any other Bevy material, you can define your own
fragment shader.

```rust
#[derive(AsBindGroup, Asset, TypePath, Clone, Default)]
pub struct FireParticleMaterial {
#[texture(0)]
#[sampler(1)]
texture: Handle,
}

impl Particle2dMaterial for FireParticleMaterial {
fn fragment_shader() -> bevy::render::render_resource::ShaderRef {
"custom_material.wgsl".into()
}
}

fn setup(){
App::default()
.add_plugins(DefaultPlugins)
.add_plugins(EnokiPlugin)
.add_plugins(Particle2dMaterialPlugin::::default())
.run()
}
```

## Create a shader

```wgsl
//assets/custom_material.wgsl
#import bevy_enoki::particle_vertex_out::{ VertexOutput }

@group(1) @binding(0) var texture: texture_2d;
@group(1) @binding(1) var texture_sampler: sampler;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4 {
var out = in.color
// go wild
return out;
}
```

That's it, now add the Material to your Spawner! These are the values provided by the vertex shader:

```wgsl
struct VertexOutput {
@builtin(position) clip_position: vec4,
@location(0) @interpolate(flat) color: vec4,
@location(1) uv : vec2,
@location(2) lifetime_frac : f32,
@location(3) lifetime_total : f32,
};
```

## The Effect Asset

[Here is a default ron config](example/assets/base.particle.ron)

```rust
#[derive(Deserialize, Default, Clone, Debug)]
pub enum EmissionShape {
#[default]
Point,
Circle(f32),
}

#[derive(Asset, TypePath, Default, Deserialize, Clone, Debug)]
pub struct Particle2dEffect {
pub spawn_rate: f32,
pub spawn_amount: u32,
pub emission_shape: EmissionShape,
pub lifetime: Rval,
pub linear_speed: Option>,
pub linear_acceleration: Option>,
pub direction: Option>,
pub angular_speed: Option>,
pub angular_acceleration: Option>,
pub scale: Option>,
pub color: Option,
pub gravity_direction: Option>,
pub gravity_speed: Option>,
pub linear_damp: Option>,
pub angular_damp: Option>,
pub scale_curve: Option>,
pub color_curve: Option>,
}
```

This how you create a `MultiCurve`. Currently, Supports `LinearRgba` and `f32`.
`RVal` stands for any Value with a randomness property between 0 - 1.

```rust
let curve = MultiCurve::new()
.with_point(LinearRgba::RED, 0.0, None)
.with_point(LinearRgba::BLUE, 1.0, Some(EaseFunction::SineInOut));

// max 1.0, randomness of 0.1 (0.9 - 1.1)
let rval = Rval::new(1.0, 0.1);
```