use bevy::{
core_pipeline::tonemapping::Tonemapping, post_process::bloom::Bloom, prelude::*,
render::view::Hdr,
};
use bevy_hanabi::prelude::*;
mod utils;
use utils::*;
const DEMO_DESC: &str = include_str!("firework.txt");
fn main() -> Result<(), Box<dyn std::error::Error>> {
let app_exit = utils::DemoApp::new("firework")
.with_desc(DEMO_DESC)
.build()
.add_systems(Startup, setup)
.run();
app_exit.into_result()
}
fn create_rocket_effect() -> EffectAsset {
let writer = ExprWriter::new();
let init_pos = SetPositionCircleModifier {
center: writer.lit(Vec3::ZERO).expr(),
axis: writer.lit(Vec3::Y).expr(),
radius: writer.lit(30.).expr(),
dimension: ShapeDimension::Volume,
};
let zero = writer.lit(0.);
let y = writer.lit(140.).uniform(writer.lit(160.));
let v = zero.clone().vec3(y, zero);
let init_vel = SetAttributeModifier::new(Attribute::VELOCITY, v.expr());
let age = writer.lit(0.).expr();
let init_age = SetAttributeModifier::new(Attribute::AGE, age);
let rgb = writer.rand(VectorType::VEC3F) * writer.lit(0.9) + writer.lit(0.1);
let color = rgb.vec4_xyz_w(writer.lit(1.)).pack4x8unorm();
let init_trails_color = SetAttributeModifier::new(Attribute::U32_0, color.expr());
let lifetime = writer.lit(0.8).uniform(writer.lit(1.2)).expr();
let init_lifetime = SetAttributeModifier::new(Attribute::LIFETIME, lifetime);
let accel = writer.lit(Vec3::Y * -16.).expr();
let update_accel = AccelModifier::new(accel);
let drag = writer.lit(4.).expr();
let update_drag = LinearDragModifier::new(drag);
let update_spawn_trail = EmitSpawnEventModifier {
condition: EventEmitCondition::Always,
count: writer.lit(5u32).expr(),
child_index: 0,
};
let update_spawn_on_die = EmitSpawnEventModifier {
condition: EventEmitCondition::OnDie,
count: writer.lit(1000u32).expr(),
child_index: 1,
};
let spawner = SpawnerSettings::rate((1., 3.).into());
EffectAsset::new(32, spawner, writer.finish())
.with_name("rocket")
.init(init_pos)
.init(init_vel)
.init(init_age)
.init(init_lifetime)
.init(init_trails_color)
.update(update_drag)
.update(update_accel)
.update(update_spawn_trail)
.update(update_spawn_on_die)
.render(ColorOverLifetimeModifier {
gradient: bevy_hanabi::Gradient::constant(Vec4::ONE),
blend: ColorBlendMode::Overwrite,
mask: ColorBlendMask::RGBA,
})
.render(SizeOverLifetimeModifier {
gradient: bevy_hanabi::Gradient::constant(Vec3::ONE * 0.1),
screen_space_size: false,
})
}
fn create_sparkle_trail_effect() -> EffectAsset {
let writer = ExprWriter::new();
let init_pos = InheritAttributeModifier::new(Attribute::POSITION);
let vel = writer.rand(VectorType::VEC3F);
let vel = vel * writer.lit(2.) - writer.lit(1.); let vel = vel.normalized();
let speed = writer.lit(1.); let vel = (vel * speed).expr();
let init_vel = SetAttributeModifier::new(Attribute::VELOCITY, vel);
let age = writer.lit(0.).expr();
let init_age = SetAttributeModifier::new(Attribute::AGE, age);
let lifetime = writer.lit(0.2).expr(); let init_lifetime = SetAttributeModifier::new(Attribute::LIFETIME, lifetime);
let accel = writer.lit(Vec3::Y * -16.).expr();
let update_accel = AccelModifier::new(accel);
let drag = writer.lit(4.).expr();
let update_drag = LinearDragModifier::new(drag);
let spawner = SpawnerSettings::default();
let mut color_gradient = bevy_hanabi::Gradient::new();
color_gradient.add_key(0.0, Vec4::new(4.0, 4.0, 4.0, 1.0));
color_gradient.add_key(0.8, Vec4::new(4.0, 4.0, 4.0, 1.0));
color_gradient.add_key(1.0, Vec4::new(4.0, 4.0, 4.0, 0.0));
EffectAsset::new(1000, spawner, writer.finish())
.with_name("sparkle_trail")
.init(init_pos)
.init(init_vel)
.init(init_age)
.init(init_lifetime)
.update(update_drag)
.update(update_accel)
.render(ColorOverLifetimeModifier {
gradient: color_gradient,
blend: ColorBlendMode::Modulate,
mask: ColorBlendMask::RGBA,
})
.render(SizeOverLifetimeModifier {
gradient: bevy_hanabi::Gradient::constant(Vec3::ONE * 0.02),
screen_space_size: false,
})
}
fn create_trails_effect() -> EffectAsset {
let writer = ExprWriter::new();
let init_pos = InheritAttributeModifier::new(Attribute::POSITION);
let init_color = SetAttributeModifier::new(
Attribute::COLOR,
writer.parent_attr(Attribute::U32_0).expr(),
);
let center = writer.attr(Attribute::POSITION);
let speed = writer.lit(40.).uniform(writer.lit(60.));
let dir = writer
.rand(VectorType::VEC3F)
.mul(writer.lit(2.0))
.sub(writer.lit(1.0))
.normalized();
let init_vel = SetAttributeModifier::new(Attribute::VELOCITY, (center + dir * speed).expr());
let age = writer.lit(0.).expr();
let init_age = SetAttributeModifier::new(Attribute::AGE, age);
let lifetime = writer.lit(0.8).uniform(writer.lit(1.2)).expr();
let init_lifetime = SetAttributeModifier::new(Attribute::LIFETIME, lifetime);
let accel = writer.lit(Vec3::Y * -16.).expr();
let update_accel = AccelModifier::new(accel);
let drag = writer.lit(4.).expr();
let update_drag = LinearDragModifier::new(drag);
let orient = OrientModifier::new(OrientMode::AlongVelocity);
let spawner = SpawnerSettings::default();
let mut color_gradient = bevy_hanabi::Gradient::new();
color_gradient.add_key(0.0, Vec4::new(4.0, 4.0, 4.0, 1.0));
color_gradient.add_key(0.6, Vec4::new(4.0, 4.0, 4.0, 1.0));
color_gradient.add_key(1.0, Vec4::new(4.0, 4.0, 4.0, 0.0));
EffectAsset::new(10000, spawner, writer.finish())
.with_name("trail")
.init(init_pos)
.init(init_vel)
.init(init_age)
.init(init_lifetime)
.init(init_color)
.update(update_drag)
.update(update_accel)
.render(ColorOverLifetimeModifier {
gradient: color_gradient,
blend: ColorBlendMode::Modulate,
mask: ColorBlendMask::RGBA,
})
.render(SizeOverLifetimeModifier {
gradient: bevy_hanabi::Gradient::constant(Vec3::new(0.2, 0.05, 0.05)),
screen_space_size: false,
})
.render(orient)
}
fn setup(mut commands: Commands, effects: ResMut<Assets<EffectAsset>>) {
commands.spawn((
Transform::from_translation(Vec3::new(0., 20., 50.)),
Camera3d::default(),
Camera {
clear_color: Color::BLACK.into(),
..default()
},
Hdr,
Tonemapping::None,
Bloom {
intensity: 0.5,
..default()
},
));
create_effect(commands, effects);
}
fn create_effect(mut commands: Commands, mut effects: ResMut<Assets<EffectAsset>>) {
let rocket_effect = effects.add(create_rocket_effect());
let rocket_entity = commands
.spawn((Name::new("rocket"), ParticleEffect::new(rocket_effect)))
.id();
let sparkle_trail_effect = effects.add(create_sparkle_trail_effect());
commands.spawn((
Name::new("sparkle_trail"),
ParticleEffect::new(sparkle_trail_effect),
EffectParent::new(rocket_entity),
));
let trails_effect = effects.add(create_trails_effect());
commands.spawn((
Name::new("trails"),
ParticleEffect::new(trails_effect),
EffectParent::new(rocket_entity),
));
}