diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index a50cc9a6a9..fcd4616023 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -12,7 +12,7 @@ in vec4 inst_mat2; in vec4 inst_mat3; in vec3 inst_col; in vec3 inst_vel; -in vec4 inst_tick; +in vec4 inst_time; in float inst_wind_sway; out vec3 f_pos; @@ -30,20 +30,10 @@ void main() { inst_mat[2] = inst_mat2; inst_mat[3] = inst_mat3; - vec3 particle_pos = (inst_mat * vec4(0, 0, 0, 1)).xyz; - f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz; - f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); + //f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); - // Wind waving - //f_pos += inst_wind_sway * vec3( - // sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35), - // sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25), - // 0.0 - //) * pow(abs(v_pos.z) * SCALE, 1.3) * 0.2; - - float elapsed = (tick.x - inst_tick.x) / 100000.0; - f_pos += (inst_vel * elapsed); + f_pos += inst_vel * (tick.x - inst_time.x); // First 3 normals are negative, next 3 are positive vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1)); @@ -53,11 +43,6 @@ void main() { f_col = srgb_to_linear(col) * srgb_to_linear(inst_col); f_ao = float((v_norm_ao >> 3) & 0x3u) / 4.0; - // Select glowing - if (select_pos.w > 0 && select_pos.xyz == floor(particle_pos)) { - f_col *= 4.0; - } - f_light = 1.0; gl_Position = diff --git a/assets/voxygen/voxel/particle.vox b/assets/voxygen/voxel/particle.vox new file mode 100644 index 0000000000..1f8fde6d26 --- /dev/null +++ b/assets/voxygen/voxel/particle.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ba07287771bbfa8f369d0d634a6f847138b605962362517af16bec1e2a7c7951 +size 64 diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index e37e6bf26d..d656e8d4e6 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -62,7 +62,7 @@ pub enum CharacterAbility { projectile: Projectile, projectile_body: Body, projectile_light: Option, - projectile_particles: Option, + projectile_particles: Vec, projectile_gravity: Option, }, Boost { @@ -261,7 +261,7 @@ impl From<&CharacterAbility> for CharacterState { projectile: projectile.clone(), projectile_body: *projectile_body, projectile_light: *projectile_light, - projectile_particles: *projectile_particles, + projectile_particles: projectile_particles.clone().to_vec(), projectile_gravity: *projectile_gravity, }), CharacterAbility::Boost { duration, only_up } => CharacterState::Boost(boost::Data { diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index fc594bd7df..e86dc1a34b 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -180,7 +180,7 @@ impl Tool { }, projectile_body: Body::Object(object::Body::Arrow), projectile_light: None, - projectile_particles: None, + projectile_particles: vec![], projectile_gravity: Some(Gravity(0.2)), }, ChargedRanged { @@ -195,7 +195,7 @@ impl Tool { recover_duration: Duration::from_millis(500), projectile_body: Body::Object(object::Body::Arrow), projectile_light: None, - projectile_particles: None, + projectile_particles: vec![], projectile_gravity: Some(Gravity(0.05)), }, ], @@ -276,7 +276,7 @@ impl Tool { col: (0.85, 0.5, 0.11).into(), ..Default::default() }), - projectile_particles: Some(ParticleEmitter { + projectile_particles: vec![ParticleEmitter { mode: ParticleEmitterMode::Sprinkler, // model_key: "voxygen.voxel.not_found", count: (2, 3), @@ -288,7 +288,8 @@ impl Tool { vek::Vec3::broadcast(1.0), ), initial_scale: (0.1, 0.3), - }), + initial_velocity: (vek::Vec3::zero(), vek::Vec3::one()), + }], projectile_gravity: None, }, BasicRanged { @@ -313,7 +314,7 @@ impl Tool { col: (1.0, 0.75, 0.11).into(), ..Default::default() }), - projectile_particles: Some(ParticleEmitter::default()), + projectile_particles: vec![ParticleEmitter::default()], projectile_gravity: None, }, ], @@ -358,7 +359,7 @@ impl Tool { col: (0.0, 1.0, 0.33).into(), ..Default::default() }), - projectile_particles: None, + projectile_particles: vec![], projectile_gravity: None, }, ], diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 4126c1a9df..3326cf2288 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -53,4 +53,4 @@ pub use player::{Player, MAX_MOUNT_RANGE_SQR}; pub use projectile::Projectile; pub use skills::{Skill, SkillGroup, SkillGroupType, SkillSet}; pub use stats::{Exp, HealthChange, HealthSource, Level, Stats}; -pub use visual::{LightAnimation, LightEmitter, ParticleEmitter}; +pub use visual::{LightAnimation, LightEmitter, ParticleEmitter, ParticleEmitters}; diff --git a/common/src/comp/visual.rs b/common/src/comp/visual.rs index 39f3f07054..fd3904dc0a 100644 --- a/common/src/comp/visual.rs +++ b/common/src/comp/visual.rs @@ -52,6 +52,13 @@ pub enum ParticleEmitterMode { Sprinkler, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] // Copy +pub struct ParticleEmitters(pub Vec); + +impl Default for ParticleEmitters { + fn default() -> Self { Self(vec![ParticleEmitter::default()]) } +} + #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct ParticleEmitter { pub mode: ParticleEmitterMode, @@ -67,6 +74,7 @@ pub struct ParticleEmitter { pub initial_offset: (Vec3, Vec3), // fn() -> Vec3, pub initial_scale: (f32, f32), // fn() -> Vec3, pub initial_orientation: (Vec3, Vec3), // fn() -> Vec3, + pub initial_velocity: (Vec3, Vec3), // fn() -> Vec3, } impl Default for ParticleEmitter { @@ -75,11 +83,15 @@ impl Default for ParticleEmitter { mode: ParticleEmitterMode::Sprinkler, // model_key: "voxygen.voxel.not_found", count: (2, 5), - frequency: Duration::from_millis(500), - initial_lifespan: Duration::from_secs(2), - initial_offset: (vek::Vec3::broadcast(-5.0), vek::Vec3::broadcast(5.0)), - initial_orientation: (vek::Vec3::broadcast(-5.0), vek::Vec3::broadcast(5.0)), + frequency: Duration::from_millis(100), + initial_lifespan: Duration::from_secs(20), + initial_offset: (vek::Vec3::broadcast(-0.1), vek::Vec3::broadcast(0.1)), + initial_orientation: (vek::Vec3::broadcast(0.0), vek::Vec3::broadcast(1.0)), initial_scale: (0.1, 2.0), + initial_velocity: ( + vek::Vec3::new(0.0, 0.0, 0.2), + vek::Vec3::new(0.01, 0.01, 1.0), + ), } } } diff --git a/common/src/event.rs b/common/src/event.rs index f291971c25..36e595154e 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -43,7 +43,7 @@ pub enum ServerEvent { dir: Dir, body: comp::Body, light: Option, - particles: Option, + particles: Vec, projectile: comp::Projectile, gravity: Option, }, diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index e8fa12c33d..2b7512e234 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -15,7 +15,7 @@ sum_type! { Stats(comp::Stats), Energy(comp::Energy), LightEmitter(comp::LightEmitter), - ParticleEmitter(comp::ParticleEmitter), + ParticleEmitter(comp::ParticleEmitters), Item(comp::Item), Scale(comp::Scale), Group(comp::Group), @@ -43,7 +43,7 @@ sum_type! { Stats(PhantomData), Energy(PhantomData), LightEmitter(PhantomData), - ParticleEmitter(PhantomData), + ParticleEmitter(PhantomData), Item(PhantomData), Scale(PhantomData), Group(PhantomData), @@ -126,7 +126,7 @@ impl sync::CompPacket for EcsCompPacket { sync::handle_remove::(entity, world) }, EcsCompPhantom::ParticleEmitter(_) => { - sync::handle_remove::(entity, world) + sync::handle_remove::(entity, world) }, EcsCompPhantom::Item(_) => sync::handle_remove::(entity, world), EcsCompPhantom::Scale(_) => sync::handle_remove::(entity, world), diff --git a/common/src/state.rs b/common/src/state.rs index c4798c5813..a06ee25dce 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -113,7 +113,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); + ecs.register::(); ecs.register::(); ecs.register::(); ecs.register::(); diff --git a/common/src/states/basic_ranged.rs b/common/src/states/basic_ranged.rs index 647b166230..8e5acaa967 100644 --- a/common/src/states/basic_ranged.rs +++ b/common/src/states/basic_ranged.rs @@ -20,7 +20,7 @@ pub struct Data { pub projectile: Projectile, pub projectile_body: Body, pub projectile_light: Option, - pub projectile_particles: Option, + pub projectile_particles: Vec, pub projectile_gravity: Option, /// Whether the attack fired already pub exhausted: bool, @@ -49,7 +49,7 @@ impl CharacterBehavior for Data { projectile: self.projectile.clone(), projectile_body: self.projectile_body, projectile_light: self.projectile_light, - projectile_particles: self.projectile_particles, + projectile_particles: self.projectile_particles.clone(), projectile_gravity: self.projectile_gravity, exhausted: false, }); @@ -63,7 +63,7 @@ impl CharacterBehavior for Data { body: self.projectile_body, projectile, light: self.projectile_light, - particles: self.projectile_particles, + particles: self.projectile_particles.clone(), gravity: self.projectile_gravity, }); @@ -75,7 +75,7 @@ impl CharacterBehavior for Data { projectile: self.projectile.clone(), projectile_body: self.projectile_body, projectile_light: self.projectile_light, - projectile_particles: self.projectile_particles, + projectile_particles: self.projectile_particles.clone(), projectile_gravity: self.projectile_gravity, exhausted: true, }); @@ -92,7 +92,7 @@ impl CharacterBehavior for Data { projectile: self.projectile.clone(), projectile_body: self.projectile_body, projectile_light: self.projectile_light, - projectile_particles: self.projectile_particles, + projectile_particles: self.projectile_particles.clone(), projectile_gravity: self.projectile_gravity, exhausted: true, }); diff --git a/server/src/cmd.rs b/server/src/cmd.rs index c6942b4090..c96265e33c 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -23,7 +23,6 @@ use specs::{Builder, Entity as EcsEntity, Join, WorldExt}; use vek::*; use world::util::Sampler; -use comp::visual::ParticleEmitterMode; use scan_fmt::{scan_fmt, scan_fmt_some}; use tracing::error; @@ -911,7 +910,7 @@ fn handle_light( .create_entity_synced() .with(pos) .with(comp::ForceUpdate) - .with(comp::ParticleEmitter::default()) + .with(comp::ParticleEmitters::default()) .with(light_emitter); if let Some(light_offset) = light_offset_opt { builder.with(light_offset).build(); diff --git a/server/src/events/entity_creation.rs b/server/src/events/entity_creation.rs index 83ff38a94c..d6725fc87f 100644 --- a/server/src/events/entity_creation.rs +++ b/server/src/events/entity_creation.rs @@ -2,11 +2,10 @@ use crate::{sys, Server, StateExt}; use common::{ comp::{ self, Agent, Alignment, Body, Gravity, Item, ItemDrop, LightEmitter, Loadout, - ParticleEmitter, Pos, Projectile, Scale, Stats, Vel, WaypointArea, + ParticleEmitter, ParticleEmitters, Pos, Projectile, Scale, Stats, Vel, WaypointArea, }, util::Dir, }; -use comp::visual::ParticleEmitterMode; use specs::{Builder, Entity as EcsEntity, WorldExt}; use vek::{Rgb, Vec3}; @@ -78,7 +77,7 @@ pub fn handle_shoot( dir: Dir, body: Body, light: Option, - particles: Option, + particles: Vec, projectile: Projectile, gravity: Option, ) { @@ -98,9 +97,7 @@ pub fn handle_shoot( if let Some(light) = light { builder = builder.with(light) } - if let Some(particles) = particles { - builder = builder.with(particles) - } + builder = builder.with(ParticleEmitters(particles)); if let Some(gravity) = gravity { builder = builder.with(gravity) } @@ -118,7 +115,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3) { flicker: 1.0, animated: true, }) - .with(ParticleEmitter::default()) + .with(ParticleEmitters::default()) .with(WaypointArea::default()) .build(); } diff --git a/server/src/sys/sentinel.rs b/server/src/sys/sentinel.rs index 0fe4af0a3d..97e86c3480 100644 --- a/server/src/sys/sentinel.rs +++ b/server/src/sys/sentinel.rs @@ -2,8 +2,8 @@ use super::SysTimer; use common::{ comp::{ Alignment, Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter, - Loadout, Mass, MountState, Mounting, Ori, ParticleEmitter, Player, Pos, Scale, Stats, - Sticky, Vel, + Loadout, Mass, MountState, Mounting, Ori, ParticleEmitter, ParticleEmitters, Player, Pos, + Scale, Stats, Sticky, Vel, }, msg::EcsCompPacket, sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt}, @@ -45,7 +45,7 @@ pub struct TrackedComps<'a> { pub energy: ReadStorage<'a, Energy>, pub can_build: ReadStorage<'a, CanBuild>, pub light_emitter: ReadStorage<'a, LightEmitter>, - pub particle_emitter: ReadStorage<'a, ParticleEmitter>, + pub particle_emitter: ReadStorage<'a, ParticleEmitters>, pub item: ReadStorage<'a, Item>, pub scale: ReadStorage<'a, Scale>, pub mounting: ReadStorage<'a, Mounting>, @@ -96,7 +96,7 @@ impl<'a> TrackedComps<'a> { .map(|c| comps.push(c.into())); self.particle_emitter .get(entity) - .copied() + .cloned() .map(|c| comps.push(c.into())); self.item.get(entity).cloned().map(|c| comps.push(c.into())); self.scale @@ -153,7 +153,7 @@ pub struct ReadTrackers<'a> { pub energy: ReadExpect<'a, UpdateTracker>, pub can_build: ReadExpect<'a, UpdateTracker>, pub light_emitter: ReadExpect<'a, UpdateTracker>, - pub particle_emitter: ReadExpect<'a, UpdateTracker>, + pub particle_emitter: ReadExpect<'a, UpdateTracker>, pub item: ReadExpect<'a, UpdateTracker>, pub scale: ReadExpect<'a, UpdateTracker>, pub mounting: ReadExpect<'a, UpdateTracker>, @@ -223,7 +223,7 @@ pub struct WriteTrackers<'a> { energy: WriteExpect<'a, UpdateTracker>, can_build: WriteExpect<'a, UpdateTracker>, light_emitter: WriteExpect<'a, UpdateTracker>, - particle_emitter: WriteExpect<'a, UpdateTracker>, + particle_emitter: WriteExpect<'a, UpdateTracker>, item: WriteExpect<'a, UpdateTracker>, scale: WriteExpect<'a, UpdateTracker>, mounting: WriteExpect<'a, UpdateTracker>, @@ -304,7 +304,7 @@ pub fn register_trackers(world: &mut World) { world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); - world.register_tracker::(); + world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); world.register_tracker::(); diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index 1352549054..37c15a4577 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -28,7 +28,7 @@ gfx_defines! { inst_mat3: [f32; 4] = "inst_mat3", inst_col: [f32; 3] = "inst_col", inst_vel: [f32; 3] = "inst_vel", - inst_tick: [f32; 4] = "inst_tick", + inst_time: [f32; 4] = "inst_time", inst_wind_sway: f32 = "inst_wind_sway", mode: u8 = "mode", } @@ -74,7 +74,7 @@ impl Instance { mat: Mat4, col: Rgb, vel: Vec3, - tick: u64, + time: f64, wind_sway: f32, mode: ParticleEmitterMode, ) -> Self { @@ -86,7 +86,7 @@ impl Instance { inst_mat3: mat_arr[3], inst_col: col.into_array(), inst_vel: vel.into_array(), - inst_tick: [tick as f32; 4], + inst_time: [time as f32; 4], inst_wind_sway: wind_sway, @@ -101,7 +101,7 @@ impl Default for Instance { Mat4::identity(), Rgb::broadcast(1.0), Vec3::zero(), - 0, + 0.0, 0.0, ParticleEmitterMode::Sprinkler, ) diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 75b41cd8d0..3ed56be91a 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -2,22 +2,23 @@ use super::SceneData; use crate::{ mesh::Meshable, render::{ - mesh::Quad, Consts, Globals, Instances, Light, Mesh, Model, ParticleInstance, - ParticlePipeline, Renderer, Shadow, + mesh::Quad, Consts, Globals, Instances, Light, Model, ParticleInstance, ParticlePipeline, + Renderer, Shadow, }, }; use common::{ assets, - comp::{visual::ParticleEmitterMode, Ori, ParticleEmitter, Pos, Vel}, + comp::{ + visual::ParticleEmitterMode, CharacterState, Ori, ParticleEmitter, ParticleEmitters, Pos, + Vel, + }, figure::Segment, - vol::BaseVol, }; use dot_vox::DotVoxData; use hashbrown::HashMap; use rand::Rng; use specs::{Entity as EcsEntity, Join, WorldExt}; use std::time::{Duration, Instant}; -use tracing::{debug, error, warn}; use vek::{Mat4, Rgb, Vec3}; struct Particles { @@ -48,7 +49,7 @@ pub struct ParticleMgr { beginning_of_time: Instant, } -const MODEL_KEY: &str = "voxygen.voxel.not_found"; +const MODEL_KEY: &str = "voxygen.voxel.particle"; impl ParticleMgr { pub fn new(renderer: &mut Renderer) -> Self { @@ -93,24 +94,34 @@ impl ParticleMgr { view_mat: Mat4, proj_mat: Mat4, ) { + let now = Instant::now(); let state = scene_data.state; let ecs = state.ecs(); - let tick = scene_data.tick; - - let now = Instant::now(); - let beginning_of_time1 = self.beginning_of_time.clone(); - // remove dead emitters self.emitters.retain(|k, _v| ecs.is_alive(*k)); // remove dead particles self.particles.retain(|p| p.alive_until > now); - // add living entities particles - for (_i, (entity, particle_emitter, pos, ori, vel)) in ( + // add ParticleEmitter particles + self.maintain_particle_emitter(renderer, scene_data); + + self.maintain_ability_particles(renderer, scene_data); + } + + fn maintain_particle_emitter(&mut self, renderer: &mut Renderer, scene_data: &SceneData) { + let state = scene_data.state; + let ecs = state.ecs(); + + let time = state.get_time(); + + let now = Instant::now(); + let beginning_of_time1 = self.beginning_of_time.clone(); + + for (_i, (entity, particle_emitters, pos, ori, vel)) in ( &ecs.entities(), - &ecs.read_storage::(), + &ecs.read_storage::(), &ecs.read_storage::(), ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), @@ -118,15 +129,78 @@ impl ParticleMgr { .join() .enumerate() { - let emitter = self.emitters.entry(entity).or_insert_with(|| Emitter { - last_emit: beginning_of_time1, // self.beginning_of_time.clone() - }); + for particle_emitter in &particle_emitters.0 { + // TODO: track multiple particle_emitter last_emit + let emitter = self.emitters.entry(entity).or_insert_with(|| Emitter { + last_emit: beginning_of_time1, // self.beginning_of_time.clone() + }); - if emitter.last_emit + particle_emitter.frequency < now { - emitter.last_emit = Instant::now(); + if emitter.last_emit + particle_emitter.frequency < now { + emitter.last_emit = Instant::now(); + + let cpu_insts = + into_particle_instances(&particle_emitter, renderer, time, pos, ori, vel); + + let gpu_insts = renderer + .create_instances(&cpu_insts) + .expect("Failed to upload particle instances to the GPU!"); + + let entry = self.particles.push(Particles { + alive_until: now + particle_emitter.initial_lifespan, + instances: gpu_insts, + }); + } + } + } + } + + fn maintain_ability_particles(&mut self, renderer: &mut Renderer, scene_data: &SceneData) { + let state = scene_data.state; + let ecs = state.ecs(); + + let time = state.get_time(); + + let now = Instant::now(); + let beginning_of_time1 = self.beginning_of_time.clone(); + + for (_i, (entity, pos, character_state)) in ( + &ecs.entities(), + //&ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ) + .join() + .enumerate() + { + // let emitter = self.emitters.entry(entity).or_insert_with(|| Emitter { + // last_emit: beginning_of_time1, // self.beginning_of_time.clone() + // }); + + // if emitter.last_emit + particle_emitter.frequency < now { + // emitter.last_emit = Instant::now(); + // } + + if let CharacterState::BasicMelee(melee_data) = character_state { + // TODO: configure the emitter on the ability instead. + let particle_emitter = ParticleEmitter { + count: (30, 50), + frequency: Duration::from_millis(1000), // doesn't matter + initial_lifespan: Duration::from_millis(1000), + initial_offset: ( + Vec3::new(1.0, -1.0, 0.0), + Vec3::new(1.01, 1.0, 2.0), /* TODO: cone // melee_data.max_angle */ + ), + initial_orientation: (Vec3::zero(), Vec3::one()), + initial_scale: (1.0, 3.0), + mode: ParticleEmitterMode::Sprinkler, + initial_velocity: ( + Vec3::new(1.0, 0.0, 0.0), + Vec3::new(10.0, 0.01, 0.01), /* TODO: cone // melee_data.max_angle */ + ), + }; let cpu_insts = - into_particle_instances(particle_emitter, renderer, tick, pos, ori, vel); + into_particle_instances(&particle_emitter, renderer, time, pos, None, None); let gpu_insts = renderer .create_instances(&cpu_insts) @@ -166,7 +240,7 @@ impl ParticleMgr { fn into_particle_instances( particle_emitter: &ParticleEmitter, renderer: &mut Renderer, - tick: u64, + time: f64, pos: &Pos, ori: Option<&Ori>, vel: Option<&Vel>, @@ -199,8 +273,13 @@ fn into_particle_instances( ), ), Rgb::broadcast(1.0), // instance color - vel2 + Vec3::broadcast(rng.gen_range(-5.0, 5.0)), - tick, + vel2 // relative + + Vec3::new( + rng.gen_range(particle_emitter.initial_velocity.0.x, particle_emitter.initial_velocity.1.x), + rng.gen_range(particle_emitter.initial_velocity.0.y, particle_emitter.initial_velocity.1.y), + rng.gen_range(particle_emitter.initial_velocity.0.z, particle_emitter.initial_velocity.1.z), + ), + time, rng.gen_range(0.0, 20.0), // wind sway ParticleEmitterMode::Sprinkler, // particle_emitter.mode */ ));