From d1bbfc99609062c5f1c137d0395db38b3ff4feeb Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 18 Aug 2020 16:51:43 +0100 Subject: [PATCH 1/9] Added BlocksOfInterest and block particle emission --- assets/voxygen/shaders/particle-frag.glsl | 6 +- assets/voxygen/shaders/particle-vert.glsl | 40 +++++++------ voxygen/src/render/pipelines/particle.rs | 2 + voxygen/src/scene/mod.rs | 3 +- voxygen/src/scene/particle.rs | 68 ++++++++++++++++++++++- voxygen/src/scene/terrain.rs | 27 ++++++++- voxygen/src/scene/terrain/watcher.rs | 37 ++++++++++++ 7 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 voxygen/src/scene/terrain/watcher.rs diff --git a/assets/voxygen/shaders/particle-frag.glsl b/assets/voxygen/shaders/particle-frag.glsl index 4dfbd6dbca..12a4ad2c3b 100644 --- a/assets/voxygen/shaders/particle-frag.glsl +++ b/assets/voxygen/shaders/particle-frag.glsl @@ -18,7 +18,7 @@ in vec3 f_pos; flat in vec3 f_norm; -in vec3 f_col; +in vec4 f_col; out vec4 tgt_color; @@ -50,7 +50,7 @@ void main() { DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, f_pos); DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac); - vec3 surf_color = f_col; + vec3 surf_color = f_col.rgb; float alpha = 1.0; const float n2 = 1.5; const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2); @@ -82,5 +82,5 @@ void main() { vec3 color = surf_color; #endif - tgt_color = vec4(color, 0.3); + tgt_color = vec4(color, f_col.a); } diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 082fc4e453..fa589067d8 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -26,7 +26,7 @@ in int inst_mode; out vec3 f_pos; flat out vec3 f_norm; -out vec3 f_col; +out vec4 f_col; out float f_ao; out float f_light; @@ -43,6 +43,7 @@ const int FIREWORK_GREEN = 5; const int FIREWORK_PURPLE = 6; const int FIREWORK_RED = 7; const int FIREWORK_YELLOW = 8; +const int LEAF = 9; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -50,7 +51,7 @@ const float earth_gravity = 9.807; struct Attr { vec3 offs; float scale; - vec3 col; + vec4 col; }; float lifetime = tick.x - inst_time; @@ -90,7 +91,7 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25) ), linear_scale(0.5), - vec3(1) + vec4(1, 1, 1, 0.3) ); } else if (inst_mode == FIRE) { attr = Attr( @@ -99,7 +100,7 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 2.0 + rand4 * 1.0) ), 1.0, - vec3(2, rand5 + 2, 0) + vec4(2, 0.8 + rand5 * 0.3, 0, 1) ); } else if (inst_mode == GUN_POWDER_SPARK) { attr = Attr( @@ -108,7 +109,7 @@ void main() { vec3(rand4, rand5, rand6) * 2.0 + grav_vel(earth_gravity) ), 1.0, - vec3(3.5, 3 + rand7, 0) + vec4(3.5, 3 + rand7, 0, 1) ); } else if (inst_mode == SHRAPNEL) { attr = Attr( @@ -117,7 +118,7 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 1) ); } else if (inst_mode == FIREWORK_BLUE) { attr = Attr( @@ -126,7 +127,7 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 0.3) ); } else if (inst_mode == FIREWORK_GREEN) { attr = Attr( @@ -135,7 +136,7 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 0.3) ); } else if (inst_mode == FIREWORK_PURPLE) { attr = Attr( @@ -144,7 +145,7 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 0.3) ); } else if (inst_mode == FIREWORK_RED) { attr = Attr( @@ -153,7 +154,7 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 0.3) ); } else if (inst_mode == FIREWORK_YELLOW) { attr = Attr( @@ -162,7 +163,16 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec3(0.6 + rand7 * 0.4) + vec4(vec3(0.6 + rand7 * 0.4), 0.3) + ); + } else if (inst_mode == LEAF) { + attr = Attr( + linear_motion( + vec3(1.0, 1.0, 0.0), + vec3(0, 0, -2.0) + ) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0, + 4, + vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1) ); } else { attr = Attr( @@ -171,7 +181,7 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5) ), exp_scale(-0.2), - vec3(1) + vec4(1) ); } @@ -179,14 +189,12 @@ void main() { // 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)); - f_norm = + f_norm = // inst_pos * normals[(v_norm_ao >> 0) & 0x7u]; //vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0; - f_col = - //srgb_to_linear(col) * - srgb_to_linear(attr.col); + f_col = vec4(srgb_to_linear(attr.col.rgb), attr.col.a); gl_Position = all_mat * diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index b2af4921f2..bb95acdfa1 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -88,6 +88,7 @@ impl Vertex { } } +#[derive(Copy, Clone)] pub enum ParticleMode { CampfireSmoke = 0, CampfireFire = 1, @@ -98,6 +99,7 @@ pub enum ParticleMode { FireworkPurple = 6, FireworkRed = 7, FireworkYellow = 8, + Leaf = 9, } impl ParticleMode { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index d69cf98c2c..b51106de00 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -942,7 +942,8 @@ impl Scene { self.figure_mgr.clean(scene_data.tick); // Maintain the particles. - self.particle_mgr.maintain(renderer, &scene_data); + self.particle_mgr + .maintain(renderer, &scene_data, &self.terrain); // Maintain audio self.sfx_mgr.maintain( diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 32f6ce5c49..96b2077b24 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -1,4 +1,4 @@ -use super::SceneData; +use super::{terrain::BlocksOfInterest, SceneData, Terrain}; use crate::{ mesh::{greedy::GreedyMesh, Meshable}, render::{ @@ -11,10 +11,14 @@ use common::{ comp::{item::Reagent, object, Body, CharacterState, Pos}, figure::Segment, outcome::Outcome, + spiral::Spiral2d, + state::DeltaTime, + terrain::TerrainChunk, + vol::RectRasterableVol, }; use dot_vox::DotVoxData; use hashbrown::HashMap; -use rand::Rng; +use rand::prelude::*; use specs::{Join, WorldExt}; use std::time::Duration; use vek::*; @@ -83,7 +87,12 @@ impl ParticleMgr { } } - pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData) { + pub fn maintain( + &mut self, + renderer: &mut Renderer, + scene_data: &SceneData, + terrain: &Terrain, + ) { if scene_data.particles_enabled { // update timings self.scheduler.maintain(scene_data.state.get_time()); @@ -95,6 +104,7 @@ impl ParticleMgr { // add new Particle self.maintain_body_particles(scene_data); self.maintain_boost_particles(scene_data); + self.maintain_block_particles(scene_data, terrain); } else { // remove all particle lifespans self.particles.clear(); @@ -245,6 +255,58 @@ impl ParticleMgr { } } + #[allow(clippy::same_item_push)] // TODO: Pending review in #587 + fn maintain_block_particles( + &mut self, + scene_data: &SceneData, + terrain: &Terrain, + ) { + let dt = scene_data.state.ecs().fetch::().0; + let time = scene_data.state.get_time(); + let player_pos = scene_data + .state + .read_component_cloned::(scene_data.player_entity) + .unwrap_or_default(); + let player_chunk = player_pos.0.xy().map2(TerrainChunk::RECT_SIZE, |e, sz| { + (e.floor() as i32).div_euclid(sz as i32) + }); + + type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3]; + let particles: &[(BoiFn, _, _, _)] = &[ + (|boi| &boi.leaves, 0.005, 30.0, ParticleMode::Leaf), + (|boi| &boi.embers, 20.0, 0.25, ParticleMode::CampfireFire), + (|boi| &boi.embers, 6.0, 30.0, ParticleMode::CampfireSmoke), + ]; + + const RANGE: usize = 4; + for offset in Spiral2d::new().take((RANGE * 2 + 1).pow(2)) { + let chunk_pos = player_chunk + offset; + + terrain.get(chunk_pos).map(|chunk_data| { + for (get_blocks, rate, dur, mode) in particles.iter() { + let blocks = get_blocks(&chunk_data.blocks_of_interest); + + let avg_particles = dt * blocks.len() as f32 * *rate; + let particle_count = avg_particles.trunc() as usize + + (thread_rng().gen::() < avg_particles.fract()) as usize; + + for _ in 0..particle_count { + let block_pos = + Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)) + + blocks.choose(&mut thread_rng()).copied().unwrap(); // Can't fail + + self.particles.push(Particle::new( + Duration::from_secs_f32(*dur), + time, + *mode, + block_pos.map(|e: i32| e as f32 + 0.5), + )); + } + } + }); + } + } + fn upload_particles(&mut self, renderer: &mut Renderer) { let all_cpu_instances = self .particles diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 06ec276b93..47cde9862b 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,3 +1,7 @@ +mod watcher; + +pub use self::watcher::BlocksOfInterest; + use crate::{ mesh::{greedy::GreedyMesh, Meshable}, render::{ @@ -35,7 +39,7 @@ enum Visibility { Visible = 2, } -struct TerrainChunkData { +pub struct TerrainChunkData { // GPU data load_time: f32, opaque_model: Model, @@ -43,6 +47,7 @@ struct TerrainChunkData { col_lights: guillotiere::AllocId, sprite_instances: HashMap<(BlockKind, usize), Instances>, locals: Consts, + pub blocks_of_interest: BlocksOfInterest, visible: Visibility, can_shadow_point: bool, @@ -51,6 +56,7 @@ struct TerrainChunkData { frustum_last_plane_index: u8, } +#[derive(Copy, Clone)] struct ChunkMeshState { pos: Vec2, started_tick: u64, @@ -67,6 +73,7 @@ struct MeshWorkerResponse { col_lights_info: ColLightInfo, sprite_instances: HashMap<(BlockKind, usize), Vec>, started_tick: u64, + blocks_of_interest: BlocksOfInterest, } struct SpriteConfig { @@ -392,6 +399,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug>( started_tick: u64, volume: as SampleVol>>::Sample, max_texture_size: u16, + chunk: Arc, range: Aabb, sprite_data: &HashMap<(BlockKind, usize), Vec>, ) -> MeshWorkerResponse { @@ -446,6 +454,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug>( instances }, + blocks_of_interest: BlocksOfInterest::from_chunk(&chunk), started_tick, } } @@ -2575,7 +2584,7 @@ impl Terrain { // Limit ourselves to u16::MAX even if larger textures are supported. let max_texture_size = renderer.max_texture_size(); - for todo in self + for (todo, chunk) in self .mesh_todo .values_mut() .filter(|todo| { @@ -2584,6 +2593,14 @@ impl Terrain { .unwrap_or(true) }) .min_by_key(|todo| todo.active_worker.unwrap_or(todo.started_tick)) + // Find a reference to the actual `TerrainChunk` we're meshing + .and_then(|todo| { + let pos = todo.pos; + Some((todo, scene_data.state + .terrain() + .get_key_arc(pos) + .cloned()?)) + }) { // TODO: find a alternative! if scene_data.thread_pool.queued_jobs() > 0 { @@ -2644,6 +2661,7 @@ impl Terrain { started_tick, volume, max_texture_size, + chunk, aabb, &sprite_data, )); @@ -2737,6 +2755,7 @@ impl Terrain { visible: Visibility::OutOfRange, can_shadow_point: false, can_shadow_sun: false, + blocks_of_interest: response.blocks_of_interest, z_bounds: response.z_bounds, frustum_last_plane_index: 0, }); @@ -2921,6 +2940,10 @@ impl Terrain { ) } + pub fn get(&self, chunk_key: Vec2) -> Option<&TerrainChunkData> { + self.chunks.get(&chunk_key) + } + pub fn chunk_count(&self) -> usize { self.chunks.len() } pub fn visible_chunk_count(&self) -> usize { diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs new file mode 100644 index 0000000000..439462f12a --- /dev/null +++ b/voxygen/src/scene/terrain/watcher.rs @@ -0,0 +1,37 @@ +use common::{ + terrain::{BlockKind, TerrainChunk}, + vol::{IntoVolIterator, RectRasterableVol}, +}; +use rand::prelude::*; +use vek::*; + +pub struct BlocksOfInterest { + pub leaves: Vec>, + pub embers: Vec>, +} + +impl BlocksOfInterest { + pub fn from_chunk(chunk: &TerrainChunk) -> Self { + let mut leaves = Vec::new(); + let mut embers = Vec::new(); + + chunk + .vol_iter( + Vec3::new(0, 0, chunk.get_min_z()), + Vec3::new( + TerrainChunk::RECT_SIZE.x as i32, + TerrainChunk::RECT_SIZE.y as i32, + chunk.get_max_z(), + ), + ) + .for_each(|(pos, block)| { + if block.kind() == BlockKind::Leaves && thread_rng().gen_range(0, 16) == 0 { + leaves.push(pos); + } else if block.kind() == BlockKind::Ember { + embers.push(pos); + } + }); + + Self { leaves, embers } + } +} From 237d33e9aa831ae44fe1b6e87a720b2b42ccf372 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 18 Aug 2020 18:06:28 +0100 Subject: [PATCH 2/9] Updated changelog --- CHANGELOG.md | 1 + voxygen/src/scene/particle.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55245f8670..ee926c7103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New level of detail feature, letting you see all the world's terrain at any view distance. - Point and directional lights now cast realistic shadows, using shadow mapping. +- Added leaf and chimney particles ### Changed - Fixed a bug where leaving the Settings menu by pressing "N" in single player kept the game paused diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 96b2077b24..ab48f0b515 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -273,7 +273,7 @@ impl ParticleMgr { type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3]; let particles: &[(BoiFn, _, _, _)] = &[ - (|boi| &boi.leaves, 0.005, 30.0, ParticleMode::Leaf), + (|boi| &boi.leaves, 0.002, 30.0, ParticleMode::Leaf), (|boi| &boi.embers, 20.0, 0.25, ParticleMode::CampfireFire), (|boi| &boi.embers, 6.0, 30.0, ParticleMode::CampfireSmoke), ]; @@ -299,7 +299,7 @@ impl ParticleMgr { Duration::from_secs_f32(*dur), time, *mode, - block_pos.map(|e: i32| e as f32 + 0.5), + block_pos.map(|e: i32| e as f32 + thread_rng().gen::()), )); } } From 0a3f0db26d935ee7a81ec90bbf078e0ff0c51d99 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Aug 2020 18:04:04 -0500 Subject: [PATCH 3/9] Added rotation to leaf particles. --- assets/voxygen/shaders/particle-vert.glsl | 51 +++++++++++++++++------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index fa589067d8..f26f53fefa 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -52,6 +52,7 @@ struct Attr { vec3 offs; float scale; vec4 col; + mat3 rot; }; float lifetime = tick.x - inst_time; @@ -72,6 +73,19 @@ float linear_scale(float factor) { return lifetime * factor; } +mat3 rotationMatrix(vec3 axis, float angle) +{ + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); +} + + void main() { float rand0 = hash(vec4(inst_entropy + 0)); float rand1 = hash(vec4(inst_entropy + 1)); @@ -81,6 +95,8 @@ void main() { float rand5 = hash(vec4(inst_entropy + 5)); float rand6 = hash(vec4(inst_entropy + 6)); float rand7 = hash(vec4(inst_entropy + 7)); + float rand8 = hash(vec4(inst_entropy + 8)); + float rand9 = hash(vec4(inst_entropy + 9)); Attr attr; @@ -91,7 +107,8 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25) ), linear_scale(0.5), - vec4(1, 1, 1, 0.3) + vec4(1, 1, 1, 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIRE) { attr = Attr( @@ -100,7 +117,8 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 2.0 + rand4 * 1.0) ), 1.0, - vec4(2, 0.8 + rand5 * 0.3, 0, 1) + vec4(2, 0.8 + rand5 * 0.3, 0, 1), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == GUN_POWDER_SPARK) { attr = Attr( @@ -109,7 +127,8 @@ void main() { vec3(rand4, rand5, rand6) * 2.0 + grav_vel(earth_gravity) ), 1.0, - vec4(3.5, 3 + rand7, 0, 1) + vec4(3.5, 3 + rand7, 0, 1), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == SHRAPNEL) { attr = Attr( @@ -118,7 +137,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 1) + vec4(vec3(0.6 + rand7 * 0.4), 1), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_BLUE) { attr = Attr( @@ -127,7 +147,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 0.3) + vec4(vec3(0.6 + rand7 * 0.4), 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_GREEN) { attr = Attr( @@ -136,7 +157,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 0.3) + vec4(vec3(0.6 + rand7 * 0.4), 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_PURPLE) { attr = Attr( @@ -145,7 +167,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 0.3) + vec4(vec3(0.6 + rand7 * 0.4), 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_RED) { attr = Attr( @@ -154,7 +177,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 0.3) + vec4(vec3(0.6 + rand7 * 0.4), 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_YELLOW) { attr = Attr( @@ -163,7 +187,8 @@ void main() { vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity) ), 3.0 + rand0, - vec4(vec3(0.6 + rand7 * 0.4), 0.3) + vec4(vec3(0.6 + rand7 * 0.4), 0.3), + rotationMatrix(vec3(1,0,0),0) ); } else if (inst_mode == LEAF) { attr = Attr( @@ -172,7 +197,8 @@ void main() { vec3(0, 0, -2.0) ) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0, 4, - vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1) + vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1), + rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) ); } else { attr = Attr( @@ -181,11 +207,12 @@ void main() { vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5) ), exp_scale(-0.2), - vec4(1) + vec4(1), + rotationMatrix(vec3(1,0,0),0) ); } - f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE + attr.offs); + f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE * attr.rot + attr.offs); // 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)); From c759c8120f3ab82d26d3437c10b9d5c5d1032368 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 19 Aug 2020 00:20:56 +0100 Subject: [PATCH 4/9] Centralised particle offset, variable chunk range, better smoke offsets --- assets/voxygen/shaders/particle-vert.glsl | 4 ++-- voxygen/src/scene/mod.rs | 6 +++--- voxygen/src/scene/particle.rs | 24 +++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index f26f53fefa..5434e8b2f0 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -104,7 +104,7 @@ void main() { attr = Attr( linear_motion( vec3(0.0, 0.0, 0.0), - vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25) + vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25) ), linear_scale(0.5), vec4(1, 1, 1, 0.3), @@ -212,7 +212,7 @@ void main() { ); } - f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE * attr.rot + attr.offs); + f_pos = (inst_pos - 0.5 - focus_off.xyz) + (v_pos * attr.scale * SCALE * attr.rot + attr.offs); // 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)); diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index b51106de00..f01ba9ec65 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -1019,12 +1019,12 @@ impl Scene { ); self.lod.render(renderer, global); - // Render particle effects. - self.particle_mgr.render(renderer, scene_data, global, lod); - // Render the skybox. renderer.render_skybox(&self.skybox.model, global, &self.skybox.locals, lod); + // Render particle effects. + self.particle_mgr.render(renderer, scene_data, global, lod); + self.terrain.render_translucent( renderer, global, diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index ab48f0b515..d63ba34432 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -157,7 +157,7 @@ impl ParticleMgr { Duration::from_secs(10), time, ParticleMode::CampfireSmoke, - pos.0, + pos.0.map(|e| e + thread_rng().gen_range(-0.5, 0.5)), )); } } @@ -272,18 +272,18 @@ impl ParticleMgr { }); type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3]; - let particles: &[(BoiFn, _, _, _)] = &[ - (|boi| &boi.leaves, 0.002, 30.0, ParticleMode::Leaf), - (|boi| &boi.embers, 20.0, 0.25, ParticleMode::CampfireFire), - (|boi| &boi.embers, 6.0, 30.0, ParticleMode::CampfireSmoke), + // blocks, chunk range, emission density, lifetime, particle mode + let particles: &[(BoiFn, usize, f32, f32, ParticleMode)] = &[ + (|boi| &boi.leaves, 4, 0.001, 30.0, ParticleMode::Leaf), + (|boi| &boi.embers, 2, 20.0, 0.25, ParticleMode::CampfireFire), + (|boi| &boi.embers, 8, 6.0, 30.0, ParticleMode::CampfireSmoke), ]; - const RANGE: usize = 4; - for offset in Spiral2d::new().take((RANGE * 2 + 1).pow(2)) { - let chunk_pos = player_chunk + offset; + for (get_blocks, range, rate, dur, mode) in particles.iter() { + for offset in Spiral2d::new().take((*range * 2 + 1).pow(2)) { + let chunk_pos = player_chunk + offset; - terrain.get(chunk_pos).map(|chunk_data| { - for (get_blocks, rate, dur, mode) in particles.iter() { + terrain.get(chunk_pos).map(|chunk_data| { let blocks = get_blocks(&chunk_data.blocks_of_interest); let avg_particles = dt * blocks.len() as f32 * *rate; @@ -302,8 +302,8 @@ impl ParticleMgr { block_pos.map(|e: i32| e as f32 + thread_rng().gen::()), )); } - } - }); + }); + } } } From d31d25b170a63241e8801d59ad2b21b9cd706d3b Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 19 Aug 2020 00:29:15 +0100 Subject: [PATCH 5/9] Added orientation to more particle modes --- assets/voxygen/shaders/particle-vert.glsl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 5434e8b2f0..861d534563 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -108,7 +108,7 @@ void main() { ), linear_scale(0.5), vec4(1, 1, 1, 0.3), - rotationMatrix(vec3(1,0,0),0) + rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) ); } else if (inst_mode == FIRE) { attr = Attr( @@ -118,7 +118,7 @@ void main() { ), 1.0, vec4(2, 0.8 + rand5 * 0.3, 0, 1), - rotationMatrix(vec3(1,0,0),0) + rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3) ); } else if (inst_mode == GUN_POWDER_SPARK) { attr = Attr( @@ -193,8 +193,8 @@ void main() { } else if (inst_mode == LEAF) { attr = Attr( linear_motion( - vec3(1.0, 1.0, 0.0), - vec3(0, 0, -2.0) + vec3(0), + vec3(0, 0, -2) ) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0, 4, vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1), @@ -215,6 +215,7 @@ void main() { f_pos = (inst_pos - 0.5 - focus_off.xyz) + (v_pos * attr.scale * SCALE * attr.rot + attr.offs); // First 3 normals are negative, next 3 are positive + // TODO: Make particle normals match orientation 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)); f_norm = // inst_pos * From 05f4024e1a86076e7479bbd49c8be2b1afe116d8 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 18 Aug 2020 19:29:24 -0500 Subject: [PATCH 6/9] Normal now rotates with particle (fixes lighting). --- assets/voxygen/shaders/particle-vert.glsl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 861d534563..3d39011bb2 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -52,7 +52,7 @@ struct Attr { vec3 offs; float scale; vec4 col; - mat3 rot; + mat4 rot; }; float lifetime = tick.x - inst_time; @@ -73,19 +73,19 @@ float linear_scale(float factor) { return lifetime * factor; } -mat3 rotationMatrix(vec3 axis, float angle) +mat4 rotationMatrix(vec3 axis, float angle) { axis = normalize(axis); float s = sin(angle); float c = cos(angle); float oc = 1.0 - c; - return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0, + 0, 0, 0, 1); } - void main() { float rand0 = hash(vec4(inst_entropy + 0)); float rand1 = hash(vec4(inst_entropy + 1)); @@ -212,14 +212,15 @@ void main() { ); } - f_pos = (inst_pos - 0.5 - focus_off.xyz) + (v_pos * attr.scale * SCALE * attr.rot + attr.offs); + f_pos = (inst_pos - focus_off.xyz) + ((v_pos - 0.5) * attr.scale * SCALE * mat3(attr.rot) + attr.offs); // First 3 normals are negative, next 3 are positive // TODO: Make particle normals match orientation - 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)); + vec4 normals[6] = vec4[](vec4(-1,0,0,0), vec4(1,0,0,0), vec4(0,-1,0,0), vec4(0,1,0,0), vec4(0,0,-1,0), vec4(0,0,1,0)); f_norm = // inst_pos * - normals[(v_norm_ao >> 0) & 0x7u]; + ((normals[(v_norm_ao >> 0) & 0x7u]) * attr.rot).xyz; + //vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0; f_col = vec4(srgb_to_linear(attr.col.rgb), attr.col.a); From 7eff8ff0ad3c55a1f29798dcabe077670c863c05 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 19 Aug 2020 21:59:17 +0100 Subject: [PATCH 7/9] Added lifetime particle parameter --- assets/voxygen/shaders/particle-vert.glsl | 10 +++++++--- voxygen/src/render/pipelines/particle.rs | 13 +++++++++++-- voxygen/src/scene/particle.rs | 6 +++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 3d39011bb2..269a3e8e41 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -21,6 +21,7 @@ in vec3 v_pos; in uint v_norm_ao; in vec3 inst_pos; in float inst_time; +in float inst_lifespan; in float inst_entropy; in int inst_mode; @@ -73,6 +74,10 @@ float linear_scale(float factor) { return lifetime * factor; } +float start_end(float from, float to) { + return mix(from, to, lifetime / inst_lifespan); +} + mat4 rotationMatrix(vec3 axis, float angle) { axis = normalize(axis); @@ -104,10 +109,10 @@ void main() { attr = Attr( linear_motion( vec3(0.0, 0.0, 0.0), - vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25) + vec3(rand2 * 0.02, rand3 * 0.02, 1.0 + rand4 * 0.1) ), linear_scale(0.5), - vec4(1, 1, 1, 0.3), + vec4(1, 1, 1, start_end(1.0, 0.0)), rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) ); } else if (inst_mode == FIRE) { @@ -221,7 +226,6 @@ void main() { // inst_pos * ((normals[(v_norm_ao >> 0) & 0x7u]) * attr.rot).xyz; - //vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0; f_col = vec4(srgb_to_linear(attr.col.rgb), attr.col.a); diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index bb95acdfa1..3088bcb298 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -24,6 +24,9 @@ gfx_defines! { // can save 32 bits per instance, for particles that are not relatively animated. inst_time: f32 = "inst_time", + // The lifespan in seconds of the particle + inst_lifespan: f32 = "inst_lifespan", + // a seed value for randomness // can save 32 bits per instance, for particles that don't need randomness/uniqueness. inst_entropy: f32 = "inst_entropy", @@ -107,10 +110,16 @@ impl ParticleMode { } impl Instance { - pub fn new(inst_time: f64, inst_mode: ParticleMode, inst_pos: Vec3) -> Self { + pub fn new( + inst_time: f64, + lifespan: f32, + inst_mode: ParticleMode, + inst_pos: Vec3, + ) -> Self { use rand::Rng; Self { inst_time: inst_time as f32, + inst_lifespan: lifespan, inst_entropy: rand::thread_rng().gen(), inst_mode: inst_mode as i32, inst_pos: inst_pos.into_array(), @@ -119,7 +128,7 @@ impl Instance { } impl Default for Instance { - fn default() -> Self { Self::new(0.0, ParticleMode::CampfireSmoke, Vec3::zero()) } + fn default() -> Self { Self::new(0.0, 0.0, ParticleMode::CampfireSmoke, Vec3::zero()) } } pub struct ParticlePipeline; diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index d63ba34432..536c2fa9f1 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -157,7 +157,7 @@ impl ParticleMgr { Duration::from_secs(10), time, ParticleMode::CampfireSmoke, - pos.0.map(|e| e + thread_rng().gen_range(-0.5, 0.5)), + pos.0.map(|e| e + thread_rng().gen_range(-0.25, 0.25)), )); } } @@ -276,7 +276,7 @@ impl ParticleMgr { let particles: &[(BoiFn, usize, f32, f32, ParticleMode)] = &[ (|boi| &boi.leaves, 4, 0.001, 30.0, ParticleMode::Leaf), (|boi| &boi.embers, 2, 20.0, 0.25, ParticleMode::CampfireFire), - (|boi| &boi.embers, 8, 6.0, 30.0, ParticleMode::CampfireSmoke), + (|boi| &boi.embers, 8, 3.0, 40.0, ParticleMode::CampfireSmoke), ]; for (get_blocks, range, rate, dur, mode) in particles.iter() { @@ -461,7 +461,7 @@ impl Particle { fn new(lifespan: Duration, time: f64, mode: ParticleMode, pos: Vec3) -> Self { Particle { alive_until: time + lifespan.as_secs_f64(), - instance: ParticleInstance::new(time, mode, pos), + instance: ParticleInstance::new(time, lifespan.as_secs_f32(), mode, pos), } } } From 1b80f05e8212965c3f2835443aa3b6200ca943d5 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 20 Aug 2020 22:34:58 +0100 Subject: [PATCH 8/9] Centred particle meshes correctly --- assets/voxygen/shaders/particle-vert.glsl | 2 +- voxygen/src/render/mesh.rs | 3 +++ voxygen/src/scene/particle.rs | 17 +++++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index 269a3e8e41..a78551a935 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -217,7 +217,7 @@ void main() { ); } - f_pos = (inst_pos - focus_off.xyz) + ((v_pos - 0.5) * attr.scale * SCALE * mat3(attr.rot) + attr.offs); + f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE * mat3(attr.rot) + attr.offs); // First 3 normals are negative, next 3 are positive // TODO: Make particle normals match orientation diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs index 4ddbe65843..cd38e88ae4 100644 --- a/voxygen/src/render/mesh.rs +++ b/voxygen/src/render/mesh.rs @@ -28,6 +28,9 @@ impl Mesh

{ /// Get a slice referencing the vertices of this mesh. pub fn vertices(&self) -> &[P::Vertex] { &self.verts } + /// Get a mutable slice referencing the vertices of this mesh. + pub fn vertices_mut(&mut self) -> &mut [P::Vertex] { &mut self.verts } + /// Push a new vertex onto the end of this mesh. pub fn push(&mut self, vert: P::Vertex) { self.verts.push(vert); } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 536c2fa9f1..2586d335a7 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -14,7 +14,7 @@ use common::{ spiral::Spiral2d, state::DeltaTime, terrain::TerrainChunk, - vol::RectRasterableVol, + vol::{RectRasterableVol, SizedVol}, }; use dot_vox::DotVoxData; use hashbrown::HashMap; @@ -367,11 +367,16 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model::generate_mesh( - Segment::from(vox.as_ref()), - &mut greedy, - ) - .0; + let segment = Segment::from(vox.as_ref()); + let segment_size = segment.size(); + let mut mesh = + Meshable::::generate_mesh(segment, &mut greedy).0; + // Center particle vertices around origin + for vert in mesh.vertices_mut() { + vert.pos[0] -= segment_size.x as f32 / 2.0; + vert.pos[1] -= segment_size.y as f32 / 2.0; + vert.pos[2] -= segment_size.z as f32 / 2.0; + } // NOTE: Ignoring coloring / lighting for now. drop(greedy); From db183e607f47a31547db5395071c1ad0ccfd6ac0 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Fri, 21 Aug 2020 09:53:09 +0100 Subject: [PATCH 9/9] Added particle explanation, more efficient particle pushing --- assets/voxygen/shaders/particle-vert.glsl | 40 +++++++++++------------ voxygen/src/scene/particle.rs | 35 +++++++++++++------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index a78551a935..7170fbc6f8 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -78,17 +78,17 @@ float start_end(float from, float to) { return mix(from, to, lifetime / inst_lifespan); } -mat4 rotationMatrix(vec3 axis, float angle) +mat4 spin_in_axis(vec3 axis, float angle) { - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0, - 0, 0, 0, 1); + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0, + 0, 0, 0, 1); } void main() { @@ -113,7 +113,7 @@ void main() { ), linear_scale(0.5), vec4(1, 1, 1, start_end(1.0, 0.0)), - rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) ); } else if (inst_mode == FIRE) { attr = Attr( @@ -123,7 +123,7 @@ void main() { ), 1.0, vec4(2, 0.8 + rand5 * 0.3, 0, 1), - rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3) + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3) ); } else if (inst_mode == GUN_POWDER_SPARK) { attr = Attr( @@ -133,7 +133,7 @@ void main() { ), 1.0, vec4(3.5, 3 + rand7, 0, 1), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == SHRAPNEL) { attr = Attr( @@ -143,7 +143,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 1), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_BLUE) { attr = Attr( @@ -153,7 +153,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 0.3), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_GREEN) { attr = Attr( @@ -163,7 +163,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 0.3), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_PURPLE) { attr = Attr( @@ -173,7 +173,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 0.3), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_RED) { attr = Attr( @@ -183,7 +183,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 0.3), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == FIREWORK_YELLOW) { attr = Attr( @@ -193,7 +193,7 @@ void main() { ), 3.0 + rand0, vec4(vec3(0.6 + rand7 * 0.4), 0.3), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } else if (inst_mode == LEAF) { attr = Attr( @@ -203,7 +203,7 @@ void main() { ) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0, 4, vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1), - rotationMatrix(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) ); } else { attr = Attr( @@ -213,7 +213,7 @@ void main() { ), exp_scale(-0.2), vec4(1), - rotationMatrix(vec3(1,0,0),0) + spin_in_axis(vec3(1,0,0),0) ); } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 2586d335a7..be555c1468 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -273,12 +273,22 @@ impl ParticleMgr { type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3]; // blocks, chunk range, emission density, lifetime, particle mode + // + // - blocks: the function to select the blocks of interest that we should emit + // from + // - chunk range: the range, in chunks, that the particles should be generated + // in from the player + // - emission density: the density, per block per second, of the generated + // particles + // - lifetime: the number of seconds that each particle should live for + // - particle mode: the visual mode of the generated particle let particles: &[(BoiFn, usize, f32, f32, ParticleMode)] = &[ (|boi| &boi.leaves, 4, 0.001, 30.0, ParticleMode::Leaf), (|boi| &boi.embers, 2, 20.0, 0.25, ParticleMode::CampfireFire), (|boi| &boi.embers, 8, 3.0, 40.0, ParticleMode::CampfireSmoke), ]; + let mut rng = thread_rng(); for (get_blocks, range, rate, dur, mode) in particles.iter() { for offset in Spiral2d::new().take((*range * 2 + 1).pow(2)) { let chunk_pos = player_chunk + offset; @@ -288,20 +298,21 @@ impl ParticleMgr { let avg_particles = dt * blocks.len() as f32 * *rate; let particle_count = avg_particles.trunc() as usize - + (thread_rng().gen::() < avg_particles.fract()) as usize; + + (rng.gen::() < avg_particles.fract()) as usize; - for _ in 0..particle_count { - let block_pos = - Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)) - + blocks.choose(&mut thread_rng()).copied().unwrap(); // Can't fail + self.particles + .resize_with(self.particles.len() + particle_count, || { + let block_pos = + Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)) + + blocks.choose(&mut rng).copied().unwrap(); // Can't fail - self.particles.push(Particle::new( - Duration::from_secs_f32(*dur), - time, - *mode, - block_pos.map(|e: i32| e as f32 + thread_rng().gen::()), - )); - } + Particle::new( + Duration::from_secs_f32(*dur), + time, + *mode, + block_pos.map(|e: i32| e as f32 + rng.gen::()), + ) + }) }); } }