mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/atmospheric-particles' into 'master'
Atmospheric Particles See merge request veloren/veloren!1310
This commit is contained in:
commit
e382e992bd
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -21,12 +21,13 @@ 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;
|
||||
|
||||
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 +44,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 +52,8 @@ const float earth_gravity = 9.807;
|
||||
struct Attr {
|
||||
vec3 offs;
|
||||
float scale;
|
||||
vec3 col;
|
||||
vec4 col;
|
||||
mat4 rot;
|
||||
};
|
||||
|
||||
float lifetime = tick.x - inst_time;
|
||||
@ -71,6 +74,23 @@ float linear_scale(float factor) {
|
||||
return lifetime * factor;
|
||||
}
|
||||
|
||||
float start_end(float from, float to) {
|
||||
return mix(from, to, lifetime / inst_lifespan);
|
||||
}
|
||||
|
||||
mat4 spin_in_axis(vec3 axis, float angle)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float rand0 = hash(vec4(inst_entropy + 0));
|
||||
float rand1 = hash(vec4(inst_entropy + 1));
|
||||
@ -80,6 +100,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;
|
||||
|
||||
@ -87,10 +109,11 @@ 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)
|
||||
),
|
||||
linear_scale(0.5),
|
||||
vec3(1)
|
||||
vec4(1, 1, 1, start_end(1.0, 0.0)),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5)
|
||||
);
|
||||
} else if (inst_mode == FIRE) {
|
||||
attr = Attr(
|
||||
@ -99,7 +122,8 @@ 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),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3)
|
||||
);
|
||||
} else if (inst_mode == GUN_POWDER_SPARK) {
|
||||
attr = Attr(
|
||||
@ -108,7 +132,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == SHRAPNEL) {
|
||||
attr = Attr(
|
||||
@ -117,7 +142,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_BLUE) {
|
||||
attr = Attr(
|
||||
@ -126,7 +152,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_GREEN) {
|
||||
attr = Attr(
|
||||
@ -135,7 +162,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_PURPLE) {
|
||||
attr = Attr(
|
||||
@ -144,7 +172,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_RED) {
|
||||
attr = Attr(
|
||||
@ -153,7 +182,8 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == FIREWORK_YELLOW) {
|
||||
attr = Attr(
|
||||
@ -162,7 +192,18 @@ 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),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
} else if (inst_mode == LEAF) {
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
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),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5)
|
||||
);
|
||||
} else {
|
||||
attr = Attr(
|
||||
@ -171,22 +212,22 @@ void main() {
|
||||
vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5)
|
||||
),
|
||||
exp_scale(-0.2),
|
||||
vec3(1)
|
||||
vec4(1),
|
||||
spin_in_axis(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 * mat3(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));
|
||||
f_norm =
|
||||
// TODO: Make particle normals match orientation
|
||||
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 =
|
||||
//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 *
|
||||
|
@ -28,6 +28,9 @@ impl<P: Pipeline> Mesh<P> {
|
||||
/// 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); }
|
||||
|
||||
|
@ -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",
|
||||
@ -88,6 +91,7 @@ impl Vertex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ParticleMode {
|
||||
CampfireSmoke = 0,
|
||||
CampfireFire = 1,
|
||||
@ -98,6 +102,7 @@ pub enum ParticleMode {
|
||||
FireworkPurple = 6,
|
||||
FireworkRed = 7,
|
||||
FireworkYellow = 8,
|
||||
Leaf = 9,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
@ -105,10 +110,16 @@ impl ParticleMode {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(inst_time: f64, inst_mode: ParticleMode, inst_pos: Vec3<f32>) -> Self {
|
||||
pub fn new(
|
||||
inst_time: f64,
|
||||
lifespan: f32,
|
||||
inst_mode: ParticleMode,
|
||||
inst_pos: Vec3<f32>,
|
||||
) -> 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(),
|
||||
@ -117,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;
|
||||
|
@ -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(
|
||||
@ -1018,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,
|
||||
|
@ -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, SizedVol},
|
||||
};
|
||||
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<TerrainChunk>,
|
||||
) {
|
||||
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();
|
||||
@ -147,7 +157,7 @@ impl ParticleMgr {
|
||||
Duration::from_secs(10),
|
||||
time,
|
||||
ParticleMode::CampfireSmoke,
|
||||
pos.0,
|
||||
pos.0.map(|e| e + thread_rng().gen_range(-0.25, 0.25)),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -245,6 +255,69 @@ impl ParticleMgr {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::same_item_push)] // TODO: Pending review in #587
|
||||
fn maintain_block_particles(
|
||||
&mut self,
|
||||
scene_data: &SceneData,
|
||||
terrain: &Terrain<TerrainChunk>,
|
||||
) {
|
||||
let dt = scene_data.state.ecs().fetch::<DeltaTime>().0;
|
||||
let time = scene_data.state.get_time();
|
||||
let player_pos = scene_data
|
||||
.state
|
||||
.read_component_cloned::<Pos>(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<i32>];
|
||||
// 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;
|
||||
|
||||
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;
|
||||
let particle_count = avg_particles.trunc() as usize
|
||||
+ (rng.gen::<f32>() < avg_particles.fract()) as usize;
|
||||
|
||||
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
|
||||
|
||||
Particle::new(
|
||||
Duration::from_secs_f32(*dur),
|
||||
time,
|
||||
*mode,
|
||||
block_pos.map(|e: i32| e as f32 + rng.gen::<f32>()),
|
||||
)
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn upload_particles(&mut self, renderer: &mut Renderer) {
|
||||
let all_cpu_instances = self
|
||||
.particles
|
||||
@ -305,11 +378,16 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model<Particl
|
||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
||||
let mut greedy = GreedyMesh::new(max_size);
|
||||
|
||||
let mesh = Meshable::<ParticlePipeline, &mut GreedyMesh>::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::<ParticlePipeline, &mut GreedyMesh>::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);
|
||||
@ -399,7 +477,7 @@ impl Particle {
|
||||
fn new(lifespan: Duration, time: f64, mode: ParticleMode, pos: Vec3<f32>) -> 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<TerrainPipeline>,
|
||||
@ -43,6 +47,7 @@ struct TerrainChunkData {
|
||||
col_lights: guillotiere::AllocId,
|
||||
sprite_instances: HashMap<(BlockKind, usize), Instances<SpriteInstance>>,
|
||||
locals: Consts<TerrainLocals>,
|
||||
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<i32>,
|
||||
started_tick: u64,
|
||||
@ -67,6 +73,7 @@ struct MeshWorkerResponse {
|
||||
col_lights_info: ColLightInfo,
|
||||
sprite_instances: HashMap<(BlockKind, usize), Vec<SpriteInstance>>,
|
||||
started_tick: u64,
|
||||
blocks_of_interest: BlocksOfInterest,
|
||||
}
|
||||
|
||||
struct SpriteConfig {
|
||||
@ -392,6 +399,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
|
||||
started_tick: u64,
|
||||
volume: <VolGrid2d<V> as SampleVol<Aabr<i32>>>::Sample,
|
||||
max_texture_size: u16,
|
||||
chunk: Arc<TerrainChunk>,
|
||||
range: Aabb<i32>,
|
||||
sprite_data: &HashMap<(BlockKind, usize), Vec<SpriteData>>,
|
||||
) -> MeshWorkerResponse {
|
||||
@ -446,6 +454,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
|
||||
|
||||
instances
|
||||
},
|
||||
blocks_of_interest: BlocksOfInterest::from_chunk(&chunk),
|
||||
started_tick,
|
||||
}
|
||||
}
|
||||
@ -2575,7 +2584,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// 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<V: RectRasterableVol> Terrain<V> {
|
||||
.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<V: RectRasterableVol> Terrain<V> {
|
||||
started_tick,
|
||||
volume,
|
||||
max_texture_size,
|
||||
chunk,
|
||||
aabb,
|
||||
&sprite_data,
|
||||
));
|
||||
@ -2737,6 +2755,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
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<V: RectRasterableVol> Terrain<V> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get(&self, chunk_key: Vec2<i32>) -> Option<&TerrainChunkData> {
|
||||
self.chunks.get(&chunk_key)
|
||||
}
|
||||
|
||||
pub fn chunk_count(&self) -> usize { self.chunks.len() }
|
||||
|
||||
pub fn visible_chunk_count(&self) -> usize {
|
||||
|
37
voxygen/src/scene/terrain/watcher.rs
Normal file
37
voxygen/src/scene/terrain/watcher.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use common::{
|
||||
terrain::{BlockKind, TerrainChunk},
|
||||
vol::{IntoVolIterator, RectRasterableVol},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
|
||||
pub struct BlocksOfInterest {
|
||||
pub leaves: Vec<Vec3<i32>>,
|
||||
pub embers: Vec<Vec3<i32>>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user