mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added frustum culling for chunks
This commit is contained in:
parent
66cd8de0e1
commit
8da46b48ac
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -782,6 +782,11 @@ name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "frustum_query"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
@ -2635,6 +2640,7 @@ dependencies = [
|
||||
"euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx_device_gl 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx_window_glutin 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2952,6 +2958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
"checksum frustum_query 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e1771c26abed26b2527d888742fffd27dab86d205bf4846748abf29c06ef5a05"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
@ -55,3 +55,4 @@ portpicker = "0.1"
|
||||
num = "0.2"
|
||||
backtrace = "0.3"
|
||||
rand = "0.5"
|
||||
frustum_query = "0.1.2"
|
||||
|
@ -151,7 +151,14 @@ impl Scene {
|
||||
.expect("Failed to update global constants");
|
||||
|
||||
// Maintain the terrain.
|
||||
self.terrain.maintain(renderer, client);
|
||||
self.terrain.maintain(
|
||||
renderer,
|
||||
client,
|
||||
self.camera.get_focus_pos(),
|
||||
self.loaded_distance,
|
||||
view_mat,
|
||||
proj_mat,
|
||||
);
|
||||
|
||||
// Maintain the figures.
|
||||
self.figure_mgr.maintain(renderer, client);
|
||||
@ -166,12 +173,7 @@ impl Scene {
|
||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||
|
||||
// Render terrain and figures.
|
||||
self.terrain.render(
|
||||
renderer,
|
||||
&self.globals,
|
||||
self.camera.get_focus_pos(),
|
||||
self.loaded_distance,
|
||||
);
|
||||
self.terrain.render(renderer, &self.globals);
|
||||
self.figure_mgr.render(renderer, client, &self.globals);
|
||||
|
||||
renderer.render_post_process(
|
||||
|
@ -8,13 +8,16 @@ use common::{
|
||||
vol::{SampleVol, VolSize},
|
||||
volumes::vol_map_2d::VolMap2dErr,
|
||||
};
|
||||
use std::{collections::HashMap, i32, sync::mpsc, time::Duration};
|
||||
use frustum_query::frustum::Frustum;
|
||||
use std::{collections::HashMap, i32, ops::Mul, sync::mpsc, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
struct TerrainChunk {
|
||||
// GPU data
|
||||
model: Model<TerrainPipeline>,
|
||||
locals: Consts<TerrainLocals>,
|
||||
visible: bool,
|
||||
z_bounds: (f32, f32),
|
||||
}
|
||||
|
||||
struct ChunkMeshState {
|
||||
@ -26,6 +29,7 @@ struct ChunkMeshState {
|
||||
/// A type produced by mesh worker threads corresponding to the position and mesh of a chunk.
|
||||
struct MeshWorkerResponse {
|
||||
pos: Vec2<i32>,
|
||||
z_bounds: (f32, f32),
|
||||
mesh: Mesh<TerrainPipeline>,
|
||||
started_tick: u64,
|
||||
}
|
||||
@ -33,12 +37,14 @@ struct MeshWorkerResponse {
|
||||
/// Function executed by worker threads dedicated to chunk meshing.
|
||||
fn mesh_worker(
|
||||
pos: Vec2<i32>,
|
||||
z_bounds: (f32, f32),
|
||||
started_tick: u64,
|
||||
volume: <TerrainMap as SampleVol<Aabr<i32>>>::Sample,
|
||||
range: Aabb<i32>,
|
||||
) -> MeshWorkerResponse {
|
||||
MeshWorkerResponse {
|
||||
pos,
|
||||
z_bounds,
|
||||
mesh: volume.generate_mesh(range),
|
||||
started_tick,
|
||||
}
|
||||
@ -70,7 +76,15 @@ impl Terrain {
|
||||
}
|
||||
|
||||
/// Maintain terrain data. To be called once per tick.
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
|
||||
pub fn maintain(
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
client: &Client,
|
||||
focus_pos: Vec3<f32>,
|
||||
loaded_distance: f32,
|
||||
view_mat: Mat4<f32>,
|
||||
proj_mat: Mat4<f32>,
|
||||
) {
|
||||
let current_tick = client.get_tick();
|
||||
|
||||
// Add any recently created or changed chunks to the list of chunks to be meshed.
|
||||
@ -165,7 +179,13 @@ impl Terrain {
|
||||
|
||||
// Queue the worker thread.
|
||||
client.thread_pool().execute(move || {
|
||||
let _ = send.send(mesh_worker(pos, current_tick, volume, aabb));
|
||||
let _ = send.send(mesh_worker(
|
||||
pos,
|
||||
(min_z as f32, max_z as f32),
|
||||
current_tick,
|
||||
volume,
|
||||
aabb,
|
||||
));
|
||||
});
|
||||
todo.active_worker = true;
|
||||
}
|
||||
@ -194,6 +214,8 @@ impl Terrain {
|
||||
.into_array(),
|
||||
}])
|
||||
.expect("Failed to upload chunk locals to the GPU!"),
|
||||
visible: false,
|
||||
z_bounds: response.z_bounds,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -202,28 +224,48 @@ impl Terrain {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
globals: &Consts<Globals>,
|
||||
focus_pos: Vec3<f32>,
|
||||
loaded_distance: f32,
|
||||
) {
|
||||
for (pos, chunk) in &self.chunks {
|
||||
// Limit focus_pos to chunk bounds
|
||||
let chunk_pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| {
|
||||
e as f32 * sz as f32
|
||||
});
|
||||
let nearest_in_chunk = Vec2::from(focus_pos).clamped(
|
||||
chunk_pos,
|
||||
chunk_pos + Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as f32),
|
||||
// Construct view frustum
|
||||
let frustum = Frustum::from_modelview_and_projection(
|
||||
&view_mat.into_col_array(),
|
||||
&proj_mat.into_col_array(),
|
||||
);
|
||||
|
||||
// Update chunk visibility
|
||||
let chunk_sz = TerrainChunkSize::SIZE.x as f32;
|
||||
for (pos, chunk) in &mut self.chunks {
|
||||
let chunk_pos = pos.map(|e| e as f32 * chunk_sz);
|
||||
|
||||
// Limit focus_pos to chunk bounds and ensure the chunk is within the fog boundary
|
||||
let nearest_in_chunk = Vec2::from(focus_pos).clamped(chunk_pos, chunk_pos + chunk_sz);
|
||||
let in_range = Vec2::<f32>::from(focus_pos).distance_squared(nearest_in_chunk)
|
||||
< loaded_distance.powf(2.0);
|
||||
|
||||
// Ensure the chunk is within the view frustrum
|
||||
let chunk_mid = Vec3::new(
|
||||
chunk_pos.x + chunk_sz / 2.0,
|
||||
chunk_pos.y + chunk_sz / 2.0,
|
||||
(chunk.z_bounds.0 + chunk.z_bounds.1) * 0.5,
|
||||
);
|
||||
let chunk_radius = (chunk.z_bounds.1 - chunk.z_bounds.0)
|
||||
.max(chunk_sz / 2.0)
|
||||
.powf(2.0)
|
||||
.mul(2.0)
|
||||
.sqrt();
|
||||
let in_frustum = frustum.sphere_intersecting(
|
||||
&chunk_mid.x,
|
||||
&chunk_mid.y,
|
||||
&chunk_mid.z,
|
||||
&chunk_radius,
|
||||
);
|
||||
|
||||
if Vec2::<f32>::from(focus_pos).distance_squared(nearest_in_chunk)
|
||||
< loaded_distance.powf(2.0)
|
||||
{
|
||||
chunk.visible = in_range && in_frustum;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
for (pos, chunk) in &self.chunks {
|
||||
if chunk.visible {
|
||||
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user