The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Added a
SimulationSpace
enum with a single valueGlobal
, in preparation of future support for local-space particle simulation. - Added
InitAgeModifier
to initialize the age of particles to a specific (possibly random) value instead of the default0.0
. - Added properties, named quantities associated with an
EffectAsset
and modifiable at runtime and assignable to values of modifiers. This enables dynamically modifying at runtime any property-based modifier value. Other non-property-based values are assumed to be constant, and are optimized by hard-coding them into the various shaders. UseEffectAsset::with_property()
andEffectAsset::add_property()
to define a new property before binding it to a modifier's value. Thespawn.rs
example demonstrates this with the acceleration of theAccelModifier
. - Added particle
Attribute
s, individual items holding a single per-particle scalar or vector value. Composed together, the attributes form the particle layout, which defines at runtime the set of per-particle values used in the simulation. This change marks a transition from the previous design where the particle attributes were hard-coded to be the position, velocity, age, and lifetime of the particle. With this change, a collection of various attributes is available for modifiers to manipulate. This ensures flexibility in customizing while retaining a minimal per-particle memory footprint for a given effect. Note that [Attribute
]s are all built-in; a custom [Attribute
] cannot be used. - Added a new
AabbKillModifier
which kills all particles entering or exiting an AABB. Theforce_field.rs
example shows an example of each variant. - Added a new
OrientAlongVelocityModifier
which orients the local X axis of particles alongside their velocity, and builds a local Z axis perpendicular to the camera view's plane. The local Y axis is derived to form an orthonormal frame.
- The
ParticleLifetimeModifier
was renamed toInitLifetimeModifer
for clarity, and itslifetime
field is now aValue<f32>
to allow randomizing per particle. - Effects no longer have a default particle lifetime of 5 seconds. Instead an explicit lifetime must be set with the
InitLifetimeModifer
. Failure to set the lifetime will trigger a warning at runtime, and particles will default to a lifetime of zero and instantly die. - The
PositionSphereModifier
was previously initializing both the position and velocity of particles. It has been split into anInitPositionSphereModifier
to initialize the position, andInitVelocitySphereModifier
to initialize the velocity. - The
PositionCircleModifier
was previously initializing both the position and velocity of particles. It has been split into anInitPositionCircleModifier
to initialize the position, andInitVelocityCircleModifier
to initialize the velocity. - Effects no longer have a default initial position similar to the ex-
PositionSphereModifier
. Add anInitPositionSphereModifier
and anInitVelocitySphereModifier
explicitly to an effect to restore the previous behavior, with a center ofVec3::ZERO
, a radius of1.
, a dimension ofShapeDimension::Volume
, and a speed of2.
. - The acceleration of the
AccelModifier
is now property-based. To dynamically change the acceleration at runtime, assign its value to an effect property withAccelModifier::via_property()
. Otherwise a constant value built withAccelModifier::constant()
can be used, and will be optimized in the update shader. See thespawn.rs
example. - All modifiers are now fully reflected (derive both
Reflect
andFromReflect
) and de/serializable. They're serialized as enums, using thetypetag
crate. ShapeDimension
now derivesDebug
and is fully reflected (derives bothReflect
andFromReflect
) and de/serializable.Value<T>
now requiresT: FromReflect
, and itself derives bothReflect
andFromReflect
.- Consequence of
Value<T>
being fully reflected, several fields onSpawner
are now fully reflected too and not ignored anymore. - The conforming to sphere feature of
ForceFieldModifier
is now applied before the Euler integration updating the particle position. This may result is tiny deviations from the previous behavior, as the particle position will not strictly conform to the sphere at the end of the step. However the delta should be very small, and no visible difference is expected in practice. - Changed the
instancing
example to allow removing particles with the BACKSPACE key in addition of the DELETE one, mainly for useability on macOS. - Changed the
lifetime
example to render particles with a colored gradient, to make the lifetime effect more clear. - The library builds with
#[deny(dead_code)]
.
- Deleted
InitLayout
,UpdateLayout
, andRenderLayout
. Init, update, and render modifiers are now directly applying themselves to theInitContext
,UpdateContext
, andRenderContext
, respectively.
- Fixed a bug breaking effect simulation after some effects are despawned and others are subsequently spawned. (#106)
- Fixed the
spawn
example failing to start on several devices due to the monitor resolution being larger than the maximum resolution imposed by the downlevel settings of WGPU. The downlevel settings are now disabled by default, and can be manually re-added for testing.
- Fix a panic on
unwrap()
after despawning N > 1 effects and re-spawning M < N effects. (#123)
- Changed the
instance.rs
example to spawn effects in random positions. Also added a (disabled) stress test which randomly spawns and despawns effects quickly to uncover bugs more easily.
- Made
Gradient<T>
reflected and serializable by implementingReflect
,FromReflect
,Serialize
, andDeserialize
.
- Fix (most common cases of) a bug where effects spawned after another effect was despawned will not work. This is a partial workaround; the bug can still trigger but under more rare conditions. (#106)
- Fix simulate compute jobs running once per view instead of once per frame. (#102)
- Fix 2D rendering not using indirect (GPU-driven) rendering.
- Fix particles being reset after another effect is despawned. (#117)
- Removed
MinMaxRect
in favor of Bevy's ownRect
type. - Removed
Resource
derive fromEffectAsset
, which made little sense on an asset.
- Add support for HDR cameras (
Camera::hdr == true
). - Add support for render layers (
RenderLayers
), allowing to select which camera(s) renders theParticleEffect
s. - Add support for linear drag force via the
LinearDragModifier
. This enables slowing down the particles over time.
- Fix a panic when running the plugin without any effect.
- Fix a bug in the way
BillboardModifier
was projecting the particle vertices onto the camera plane, producing some partial or total clipping of particles.
- Switch to Bevy v0.9.
- Disabled broken effect batching until #73 is fixed, to prevent triggering batching which breaks rendering.
- Switched to a new internal architecture, splitting the initializing of newly spawned particles from the updating of all alive particles, to achieve more consistent workload on the update compute. Added GPU-driven compute dispatch and rendering, which slighly improves performance and reduces CPU dependency/synchronization. This is mostly an internal change, but with the potential to unblock or facilitate several other issues. (#19)
- Removed
ParticleEffect::spawner()
from the public API, which was intended for internal use and is a bit confusing. - Renamed the oddly-named
RenderLayout::size_color_gradient
into the more understandableRenderLayout::lifetime_size_gradient
. - Renamed
PipelineRegistry
intoShaderCache
, and itsconfigure()
method intoget_or_insert()
, for clarity.
- Prevent
ShaderCache::get_or_insert()
from unnecessarily triggering change detection onAssets<Shader>
when the item is already in the cache.
- Respect user-defined MSAA setting by reading the value of
Msaa::samples
when building the render pipeline. (#59) - Fixed a bug in the effect cache causing a panic sometimes when effects are removed. (#60)
- Fixed a bug where an effect instance would be allocated overwriting another existing instance.
- Fixed a bug in the calculation of some GPU buffer binding causing a panic under some combination of effect capacity and spawn count. (#68)
- Added
PositionCone3dModifier
to spawn particles inside a truncated 3D cone. - All GPU profiling markers are now prefixed with
hanabi:
to make it easier to find Hanabi-related GPU resources.
- Moved all modifiers into a top-level
modifier
module, and further into someinit
,update
, andrender
sub-modules. - Added a
bevy_hanabi::prelude
containing most public types, to be used preferably overuse bevy_hanabi::*
. - Renamed
ForceFieldParam
toForceFieldSource
. - Renamed the
FFNUM
constant toForceFieldSource::MAX_SOURCES
. - Renamed
ForceFieldModifier::force_field
toForceFieldModifier::sources
.
- The orientation of the
Entity
of theParticleEffect
is now taken into account for spawning. (#42) - Ensure all GPU resources are deallocated when a
ParticleEffect
component is despawned. (#45)
EffectCacheId
is now private. It was exposed publicly by error, and cannot be used for anything in the public API anyway.
- Added
EffectAsset::z_layer_2d
andParticleEffect::z_layer_2d
to control the Z layer at which particles are rendered in 2D mode. Note that effects with different Z values cannot be batched together, which may negatively affect performance. - Added
BillboardModifier
to force the particles to face the camera.
- Switch to Bevy v0.8.
- Update spawners in a separate system
tick_spawners()
(label:EffectSystems::TickSpawners
) which runs in theCoreStage::PostUpdate
stage after the visibility system updated allComputedVisibility
, to allow skipping effect instances which are not visible. Spawners were previously ticked in the render extract phase.
- Added test-only feature
gpu_tests
active by default to enable tests requiring a working graphic adapter (GPU). This is disabled in most CI tests, except on Linux where the CPU-based Vulkan emulatorlavapipe
is used.
- Switch to Bevy v0.7.
- Changed features
2d
and3d
to be purely additive. They are now both active by default, allowing to render through both 2D and 3D cameras at the same time. Users can optionally select either of those exclusively via the--no-default-features --features='2d'
options (or similar for 3D), as an optimization for applications using only one of the two codepaths. - Tighter set of dependencies, removing the general
bevy/render
and instead depending onbevy/bevy_core_pipeline
andbevy/bevy_render
only.
- Fix missing
derive
feature inbytemuck
dependency occasionally causing build errors. - Fix a bug in spawner parameters alignment making the library crash on some GPUs. The spawner parameters are now properly aligned according to the device-dependent constraints queried at runtime. (#26)
- Add
SizeOverLifetimeModifier
. - Add
PositionCircleModifier
to allow spawning from a circle or disc. - Revamped spawning system:
SpawnMode
is gone;Spawner
s are constructed with associated functionsnew
,once
,rate
, andburst
.- Spawners can be reset with
Spawner::reset
. This gives control over when to spawn a burst of particles. - Spawners can be activated or deactivated with
Spawner::set_active
. ParticleEffectBundle
s can be initialized with a spawner withParticleEffectBundle::with_spawner
.
- Implemented
ToWgslFloat
forVec2
/Vec3
/Vec4
. - Implemented
ToWgslFloat
forValue<f32>
. - Derive-implemented
PartialEq
forValue<T>
andSpawner
. - Implemented randomization for randomized spawning parameters
- New force field effect:
- Add
ForceFieldModifier
to allow attraction or repulsion from point sources. - Add
ForceFieldParam
in both the modifiers and the particle update shader. - Add
force_field
example showcasing a repulsor, an attractor and the conforming to sphere functionality.
- Add
- Add rendering with a 2D camera.
- Renamed the
ToWgslFloat
trait intoToWgslString
, and itsto_float_string()
method intoto_wgsl_string()
. Also made the trait public. - Position modifiers now use
Value<f32>
for velocity to allow for random velocity. - Either the "3d" feature or the "2d" feature must be enabled.
- Fixed depth sorting of particles relative to opaque objects. Particles are now correctly hidden when behind opaque objects.
- Fixed truncation in compute workgroup count preventing update of some particles, and in degenerate cases (
capacity < 64
) completely disabling update. - Made the
GradientKey<T>::ratio
field private to avoid any modification viaGradient<T>::keys_mut()
which would corrupt the internal sorting of keys. - Fixed a bug where adding the
HanabiPlugin
to an app without spawning anyParticleEffect
would crash at runtime. (#9).
- Fix homepage link in
Cargo.toml
- Bevy 0.6.1 fixed build on nightly, thereby fixing docs.rs builds
Initial alpha version. Lots of things missing, but the barebone functionality is there. See the README.md for the list of planned and implemented features.