diff --git a/CHANGELOG.md b/CHANGELOG.md index d927b9986c..ab2470589d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Lactose tolerant golems - 6 different gems. (Topaz, Amethyst, Sapphire, Emerald, Ruby and Diamond) - Poise system (not currently accessible to players for balancing reasons) +- Snow particles ### Changed diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index ba4b815033..e7a9b75237 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -15,6 +15,7 @@ #include #include #include +#include in vec3 v_pos; // in uint v_col; @@ -55,6 +56,7 @@ const int ENERGY_NATURE = 14; const int FLAMETHROWER = 15; const int FIRE_SHOCKWAVE = 16; const int FIRE_BOWL = 17; +const int SNOW = 18; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -140,6 +142,8 @@ void main() { float rand8 = hash(vec4(inst_entropy + 8)); float rand9 = hash(vec4(inst_entropy + 9)); + vec3 start_pos = inst_pos - focus_off.xyz; + Attr attr; f_reflect = 1.0; @@ -260,6 +264,17 @@ void main() { vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1), spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) ); + } else if (inst_mode == SNOW) { + float height = mix(-4, 60, pow(start_end(1, 0), 3)); + float wind_speed = (inst_pos.z - 250) * 0.025; + vec3 offset = linear_motion(vec3(0), vec3(1, 1, 0) * wind_speed); + float end_alt = alt_at(start_pos.xy + offset.xy); + attr = Attr( + offset + vec3(0, 0, end_alt - start_pos.z + height) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 3, + vec3(mix(4, 0, pow(start_end(1, 0), 4))), + vec4(1), + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) + ); } else if (inst_mode == FIREFLY) { float raise = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2); attr = Attr( @@ -341,7 +356,7 @@ void main() { // Temporary: use shrinking particles as a substitute for fading ones attr.scale *= pow(attr.col.a, 0.25); - f_pos = (inst_pos - focus_off.xyz) + (v_pos * attr.scale * SCALE * mat3(attr.rot) + attr.offs); + f_pos = start_pos + (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/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index 86c3d56bc2..224587f429 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -114,6 +114,7 @@ pub enum ParticleMode { FlameThrower = 15, FireShockwave = 16, FireBowl = 17, + Snow = 18, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index d85c831b02..b9b4b8cf21 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -522,6 +522,14 @@ impl ParticleMgr { mode: ParticleMode::Bee, cond: |sd| sd.state.get_day_period().is_light(), }, + BlockParticles { + blocks: |boi| &boi.snow, + range: 4, + rate: 0.025, + lifetime: 15.0, + mode: ParticleMode::Snow, + cond: |_| true, + }, ]; let mut rng = thread_rng(); diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 43034d2091..02cfdbb087 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -17,6 +17,7 @@ pub struct BlocksOfInterest { pub reeds: Vec>, pub flowers: Vec>, pub fire_bowls: Vec>, + pub snow: Vec>, // Note: these are only needed for chunks within the iteraction range so this is a potential // area for optimization pub interactables: Vec>, @@ -37,6 +38,7 @@ impl BlocksOfInterest { let mut interactables = Vec::new(); let mut lights = Vec::new(); let mut fire_bowls = Vec::new(); + let mut snow = Vec::new(); chunk .vol_iter( @@ -49,21 +51,14 @@ impl BlocksOfInterest { ) .for_each(|(pos, block)| { match block.kind() { - BlockKind::Leaves => { - if thread_rng().gen_range(0..16) == 0 { - leaves.push(pos) - } - }, - BlockKind::Grass => { - if thread_rng().gen_range(0..16) == 0 { - grass.push(pos) - } - }, - BlockKind::Water => { - if chunk.meta().contains_river() && thread_rng().gen_range(0..16) == 0 { - river.push(pos) - } + BlockKind::Leaves if thread_rng().gen_range(0..16) == 0 => leaves.push(pos), + BlockKind::Grass if thread_rng().gen_range(0..16) == 0 => grass.push(pos), + BlockKind::Water + if chunk.meta().contains_river() && thread_rng().gen_range(0..16) == 0 => + { + river.push(pos) }, + BlockKind::Snow if thread_rng().gen_range(0..16) == 0 => snow.push(pos), _ => match block.get_sprite() { Some(SpriteKind::Ember) => { fires.push(pos); @@ -107,6 +102,7 @@ impl BlocksOfInterest { interactables, lights, fire_bowls, + snow, } } }