mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added basic culling of underground terrain and sprites
This commit is contained in:
parent
589fddab4e
commit
661b587c9f
@ -868,7 +868,7 @@ pub fn create_quad<O: Vertex, M>(
|
|||||||
draw_dim: Vec2<Vec3<f32>>,
|
draw_dim: Vec2<Vec3<f32>>,
|
||||||
norm: Vec3<f32>,
|
norm: Vec3<f32>,
|
||||||
meta: &M,
|
meta: &M,
|
||||||
create_vertex: impl Fn(Vec2<u16>, Vec3<f32>, Vec3<f32>, &M) -> O,
|
mut create_vertex: impl FnMut(Vec2<u16>, Vec3<f32>, Vec3<f32>, &M) -> O,
|
||||||
) -> Quad<O> {
|
) -> Quad<O> {
|
||||||
Quad::new(
|
Quad::new(
|
||||||
create_vertex(atlas_pos, origin, norm, meta),
|
create_vertex(atlas_pos, origin, norm, meta),
|
||||||
|
@ -5,8 +5,8 @@ use crate::{
|
|||||||
greedy::{self, GreedyConfig, GreedyMesh},
|
greedy::{self, GreedyConfig, GreedyMesh},
|
||||||
MeshGen,
|
MeshGen,
|
||||||
},
|
},
|
||||||
render::{ColLightInfo, FluidVertex, Mesh, TerrainVertex},
|
render::{ColLightInfo, FluidVertex, Mesh, TerrainVertex, Vertex},
|
||||||
scene::terrain::BlocksOfInterest,
|
scene::terrain::{AltIndices, BlocksOfInterest, DEEP_ALT, SHALLOW_ALT},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::{Block, TerrainChunk},
|
terrain::{Block, TerrainChunk},
|
||||||
@ -238,6 +238,7 @@ pub fn generate_mesh<'a>(
|
|||||||
ColLightInfo,
|
ColLightInfo,
|
||||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||||
|
AltIndices,
|
||||||
),
|
),
|
||||||
> {
|
> {
|
||||||
span!(
|
span!(
|
||||||
@ -275,6 +276,12 @@ pub fn generate_mesh<'a>(
|
|||||||
let light = calc_light(true, SUNLIGHT, range, vol, core::iter::empty());
|
let light = calc_light(true, SUNLIGHT, range, vol, core::iter::empty());
|
||||||
let glow = calc_light(false, 0, range, vol, glow_blocks.into_iter());
|
let glow = calc_light(false, 0, range, vol, glow_blocks.into_iter());
|
||||||
|
|
||||||
|
let (underground_alt, deep_alt) = vol
|
||||||
|
.get_key(vol.pos_key((range.min + range.max) / 2))
|
||||||
|
.map_or((0.0, 0.0), |c| {
|
||||||
|
(c.meta().alt() - SHALLOW_ALT, c.meta().alt() - DEEP_ALT)
|
||||||
|
});
|
||||||
|
|
||||||
let mut opaque_limits = None::<Limits>;
|
let mut opaque_limits = None::<Limits>;
|
||||||
let mut fluid_limits = None::<Limits>;
|
let mut fluid_limits = None::<Limits>;
|
||||||
let mut air_limits = None::<Limits>;
|
let mut air_limits = None::<Limits>;
|
||||||
@ -424,7 +431,9 @@ pub fn generate_mesh<'a>(
|
|||||||
|
|
||||||
let mut greedy =
|
let mut greedy =
|
||||||
GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(max_size, greedy::general_config());
|
GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(max_size, greedy::general_config());
|
||||||
let mut opaque_mesh = Mesh::new();
|
let mut opaque_deep = Vec::new();
|
||||||
|
let mut opaque_shallow = Vec::new();
|
||||||
|
let mut opaque_surface = Vec::new();
|
||||||
let mut fluid_mesh = Mesh::new();
|
let mut fluid_mesh = Mesh::new();
|
||||||
greedy.push(GreedyConfig {
|
greedy.push(GreedyConfig {
|
||||||
data: (),
|
data: (),
|
||||||
@ -438,15 +447,31 @@ pub fn generate_mesh<'a>(
|
|||||||
should_draw,
|
should_draw,
|
||||||
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta {
|
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta {
|
||||||
FaceKind::Opaque(meta) => {
|
FaceKind::Opaque(meta) => {
|
||||||
opaque_mesh.push_quad(greedy::create_quad(
|
let mut max_z = None;
|
||||||
|
let mut min_z = None;
|
||||||
|
let quad = greedy::create_quad(
|
||||||
atlas_origin,
|
atlas_origin,
|
||||||
dim,
|
dim,
|
||||||
origin,
|
origin,
|
||||||
draw_dim,
|
draw_dim,
|
||||||
norm,
|
norm,
|
||||||
meta,
|
meta,
|
||||||
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
|atlas_pos, pos, norm, &meta| {
|
||||||
));
|
max_z = Some(max_z.map_or(pos.z, |z: f32| z.max(pos.z)));
|
||||||
|
min_z = Some(min_z.map_or(pos.z, |z: f32| z.min(pos.z)));
|
||||||
|
create_opaque(atlas_pos, pos, norm, meta)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let max_alt = mesh_delta.z as f32 + max_z.unwrap_or(0.0);
|
||||||
|
let min_alt = mesh_delta.z as f32 + min_z.unwrap_or(0.0);
|
||||||
|
|
||||||
|
if max_alt < deep_alt {
|
||||||
|
opaque_deep.push(quad);
|
||||||
|
} else if min_alt > underground_alt {
|
||||||
|
opaque_surface.push(quad);
|
||||||
|
} else {
|
||||||
|
opaque_shallow.push(quad);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
FaceKind::Fluid => {
|
FaceKind::Fluid => {
|
||||||
fluid_mesh.push_quad(greedy::create_quad(
|
fluid_mesh.push_quad(greedy::create_quad(
|
||||||
@ -472,8 +497,29 @@ pub fn generate_mesh<'a>(
|
|||||||
};
|
};
|
||||||
let (col_lights, col_lights_size) = greedy.finalize();
|
let (col_lights, col_lights_size) = greedy.finalize();
|
||||||
|
|
||||||
|
let deep_end = opaque_deep.len()
|
||||||
|
* if TerrainVertex::QUADS_INDEX.is_some() {
|
||||||
|
4
|
||||||
|
} else {
|
||||||
|
6
|
||||||
|
};
|
||||||
|
let alt_indices = AltIndices {
|
||||||
|
deep_end,
|
||||||
|
underground_end: deep_end
|
||||||
|
+ opaque_shallow.len()
|
||||||
|
* if TerrainVertex::QUADS_INDEX.is_some() {
|
||||||
|
4
|
||||||
|
} else {
|
||||||
|
6
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
opaque_mesh,
|
opaque_deep
|
||||||
|
.into_iter()
|
||||||
|
.chain(opaque_shallow.into_iter())
|
||||||
|
.chain(opaque_surface.into_iter())
|
||||||
|
.collect(),
|
||||||
fluid_mesh,
|
fluid_mesh,
|
||||||
Mesh::new(),
|
Mesh::new(),
|
||||||
(
|
(
|
||||||
@ -481,6 +527,7 @@ pub fn generate_mesh<'a>(
|
|||||||
(col_lights, col_lights_size),
|
(col_lights, col_lights_size),
|
||||||
Arc::new(light),
|
Arc::new(light),
|
||||||
Arc::new(glow),
|
Arc::new(glow),
|
||||||
|
alt_indices,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,26 @@
|
|||||||
use super::buffer::DynamicBuffer;
|
use super::buffer::DynamicBuffer;
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
/// Represents a set of instances that has been sent to the GPU.
|
||||||
|
pub struct SubInstances<'a, T: Copy + Pod> {
|
||||||
|
pub inst_range: Range<u32>,
|
||||||
|
buf: &'a wgpu::Buffer,
|
||||||
|
phantom_data: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Copy + Pod> SubInstances<'a, T> {
|
||||||
|
pub(super) fn buf(&self) -> wgpu::BufferSlice<'a> {
|
||||||
|
let start = self.inst_range.start as wgpu::BufferAddress
|
||||||
|
* std::mem::size_of::<T>() as wgpu::BufferAddress;
|
||||||
|
let end = self.inst_range.end as wgpu::BufferAddress
|
||||||
|
* std::mem::size_of::<T>() as wgpu::BufferAddress;
|
||||||
|
self.buf.slice(start..end)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
pub fn count(&self) -> u32 { self.inst_range.end - self.inst_range.start }
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the GPU.
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
pub struct Instances<T: Copy + Pod> {
|
pub struct Instances<T: Copy + Pod> {
|
||||||
@ -15,6 +36,16 @@ impl<T: Copy + Pod> Instances<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a set of instances with a slice of a portion of these instances
|
||||||
|
/// to send to the renderer.
|
||||||
|
pub fn subinstances(&self, inst_range: Range<u32>) -> SubInstances<T> {
|
||||||
|
SubInstances {
|
||||||
|
inst_range,
|
||||||
|
buf: self.buf(),
|
||||||
|
phantom_data: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: count vs len naming scheme??
|
// TODO: count vs len naming scheme??
|
||||||
pub fn count(&self) -> usize { self.buf.len() }
|
pub fn count(&self) -> usize { self.buf.len() }
|
||||||
|
|
||||||
|
@ -124,7 +124,11 @@ impl<V: Vertex> IntoIterator for Mesh<V> {
|
|||||||
|
|
||||||
impl<V: Vertex> FromIterator<Tri<V>> for Mesh<V> {
|
impl<V: Vertex> FromIterator<Tri<V>> for Mesh<V> {
|
||||||
fn from_iter<I: IntoIterator<Item = Tri<V>>>(tris: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = Tri<V>>>(tris: I) -> Self {
|
||||||
tris.into_iter().fold(Self::new(), |mut this, tri| {
|
let mut this = Self::new();
|
||||||
|
let tris = tris.into_iter();
|
||||||
|
let (lower, upper) = tris.size_hint();
|
||||||
|
this.verts.reserve(3 * upper.unwrap_or(lower));
|
||||||
|
tris.fold(this, |mut this, tri| {
|
||||||
this.push_tri(tri);
|
this.push_tri(tri);
|
||||||
this
|
this
|
||||||
})
|
})
|
||||||
@ -133,7 +137,12 @@ impl<V: Vertex> FromIterator<Tri<V>> for Mesh<V> {
|
|||||||
|
|
||||||
impl<V: Vertex> FromIterator<Quad<V>> for Mesh<V> {
|
impl<V: Vertex> FromIterator<Quad<V>> for Mesh<V> {
|
||||||
fn from_iter<I: IntoIterator<Item = Quad<V>>>(quads: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = Quad<V>>>(quads: I) -> Self {
|
||||||
quads.into_iter().fold(Self::new(), |mut this, quad| {
|
let mut this = Self::new();
|
||||||
|
let quads = quads.into_iter();
|
||||||
|
let (lower, upper) = quads.size_hint();
|
||||||
|
this.verts
|
||||||
|
.reserve(if V::QUADS_INDEX.is_some() { 4 } else { 6 } * upper.unwrap_or(lower));
|
||||||
|
quads.fold(this, |mut this, quad| {
|
||||||
this.push_quad(quad);
|
this.push_quad(quad);
|
||||||
this
|
this
|
||||||
})
|
})
|
||||||
|
@ -975,7 +975,16 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
|||||||
model: &'data Model<terrain::Vertex>,
|
model: &'data Model<terrain::Vertex>,
|
||||||
col_lights: &'data Arc<ColLights<terrain::Locals>>,
|
col_lights: &'data Arc<ColLights<terrain::Locals>>,
|
||||||
locals: &'data terrain::BoundLocals,
|
locals: &'data terrain::BoundLocals,
|
||||||
|
alt_indices: &'data crate::scene::terrain::AltIndices,
|
||||||
|
is_underground: bool,
|
||||||
) {
|
) {
|
||||||
|
// Don't render anything if there's nothing to render!
|
||||||
|
if (alt_indices.underground_end == 0 && is_underground)
|
||||||
|
|| (alt_indices.deep_end == model.len() && !is_underground)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if self.col_lights
|
if self.col_lights
|
||||||
// Check if we are still using the same atlas texture as the previous drawn
|
// Check if we are still using the same atlas texture as the previous drawn
|
||||||
// chunk
|
// chunk
|
||||||
@ -988,9 +997,16 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
||||||
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
|
|
||||||
|
let submodel = if is_underground {
|
||||||
|
model.submodel(0..alt_indices.underground_end as u32)
|
||||||
|
} else {
|
||||||
|
model.submodel(alt_indices.deep_end as u32..model.len() as u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.render_pass.set_vertex_buffer(0, submodel.buf());
|
||||||
self.render_pass
|
self.render_pass
|
||||||
.draw_indexed(0..model.len() as u32 / 4 * 6, 0, 0..1);
|
.draw_indexed(0..submodel.len() as u32 / 4 * 6, 0, 0..1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,16 +1043,30 @@ impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
terrain_locals: &'data terrain::BoundLocals,
|
terrain_locals: &'data terrain::BoundLocals,
|
||||||
instances: &'data Instances<sprite::Instance>,
|
instances: &'data Instances<sprite::Instance>,
|
||||||
|
alt_indices: &'data crate::scene::terrain::AltIndices,
|
||||||
|
is_underground: bool,
|
||||||
) {
|
) {
|
||||||
|
// Don't render anything if there's nothing to render!
|
||||||
|
if (alt_indices.underground_end == 0 && is_underground)
|
||||||
|
|| (alt_indices.deep_end == instances.count() && !is_underground)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.render_pass
|
self.render_pass
|
||||||
.set_bind_group(3, &terrain_locals.bind_group, &[]);
|
.set_bind_group(3, &terrain_locals.bind_group, &[]);
|
||||||
|
|
||||||
self.render_pass
|
let subinstances = if is_underground {
|
||||||
.set_vertex_buffer(0, instances.buf().slice(..));
|
instances.subinstances(0..alt_indices.underground_end as u32)
|
||||||
|
} else {
|
||||||
|
instances.subinstances(alt_indices.deep_end as u32..instances.count() as u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.render_pass.set_vertex_buffer(0, subinstances.buf());
|
||||||
self.render_pass.draw_indexed(
|
self.render_pass.draw_indexed(
|
||||||
0..sprite::VERT_PAGE_SIZE / 4 * 6,
|
0..sprite::VERT_PAGE_SIZE / 4 * 6,
|
||||||
0,
|
0,
|
||||||
0..instances.count() as u32,
|
0..subinstances.count() as u32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1246,6 +1246,13 @@ impl Scene {
|
|||||||
let focus_pos = self.camera.get_focus_pos();
|
let focus_pos = self.camera.get_focus_pos();
|
||||||
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
|
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
|
||||||
let is_rain = state.max_weather_near(cam_pos.xy()).rain > RAIN_THRESHOLD;
|
let is_rain = state.max_weather_near(cam_pos.xy()).rain > RAIN_THRESHOLD;
|
||||||
|
let is_underground = scene_data
|
||||||
|
.state
|
||||||
|
.terrain()
|
||||||
|
.get_key(scene_data.state.terrain().pos_key(focus_pos.as_()))
|
||||||
|
.map_or(false, |c| {
|
||||||
|
focus_pos.z < c.meta().alt() - (terrain::SHALLOW_ALT + terrain::DEEP_ALT) / 2.0
|
||||||
|
});
|
||||||
|
|
||||||
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
|
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
|
||||||
|
|
||||||
@ -1305,7 +1312,8 @@ impl Scene {
|
|||||||
camera_data,
|
camera_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.terrain.render(&mut first_pass, focus_pos);
|
self.terrain
|
||||||
|
.render(&mut first_pass, focus_pos, is_underground);
|
||||||
|
|
||||||
self.figure_mgr.render(
|
self.figure_mgr.render(
|
||||||
&mut first_pass.draw_figures(),
|
&mut first_pass.draw_figures(),
|
||||||
@ -1326,6 +1334,7 @@ impl Scene {
|
|||||||
focus_pos,
|
focus_pos,
|
||||||
cam_pos,
|
cam_pos,
|
||||||
scene_data.sprite_render_distance,
|
scene_data.sprite_render_distance,
|
||||||
|
is_underground,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Render particle effects.
|
// Render particle effects.
|
||||||
|
@ -89,7 +89,7 @@ pub struct TerrainChunkData {
|
|||||||
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
|
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
|
||||||
light_map: LightMapFn,
|
light_map: LightMapFn,
|
||||||
glow_map: LightMapFn,
|
glow_map: LightMapFn,
|
||||||
sprite_instances: [Instances<SpriteInstance>; SPRITE_LOD_LEVELS],
|
sprite_instances: [(Instances<SpriteInstance>, AltIndices); SPRITE_LOD_LEVELS],
|
||||||
locals: pipelines::terrain::BoundLocals,
|
locals: pipelines::terrain::BoundLocals,
|
||||||
pub blocks_of_interest: BlocksOfInterest,
|
pub blocks_of_interest: BlocksOfInterest,
|
||||||
|
|
||||||
@ -98,6 +98,16 @@ pub struct TerrainChunkData {
|
|||||||
can_shadow_sun: bool,
|
can_shadow_sun: bool,
|
||||||
z_bounds: (f32, f32),
|
z_bounds: (f32, f32),
|
||||||
frustum_last_plane_index: u8,
|
frustum_last_plane_index: u8,
|
||||||
|
|
||||||
|
alt_indices: AltIndices,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const SHALLOW_ALT: f32 = 24.0;
|
||||||
|
pub const DEEP_ALT: f32 = 96.0;
|
||||||
|
|
||||||
|
pub struct AltIndices {
|
||||||
|
pub deep_end: usize,
|
||||||
|
pub underground_end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -117,13 +127,14 @@ pub struct MeshWorkerResponseMesh {
|
|||||||
col_lights_info: ColLightInfo,
|
col_lights_info: ColLightInfo,
|
||||||
light_map: LightMapFn,
|
light_map: LightMapFn,
|
||||||
glow_map: LightMapFn,
|
glow_map: LightMapFn,
|
||||||
|
alt_indices: AltIndices,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type produced by mesh worker threads corresponding to the position and
|
/// A type produced by mesh worker threads corresponding to the position and
|
||||||
/// mesh of a chunk.
|
/// mesh of a chunk.
|
||||||
struct MeshWorkerResponse {
|
struct MeshWorkerResponse {
|
||||||
pos: Vec2<i32>,
|
pos: Vec2<i32>,
|
||||||
sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
|
sprite_instances: [(Vec<SpriteInstance>, AltIndices); SPRITE_LOD_LEVELS],
|
||||||
/// If None, this update was requested without meshing.
|
/// If None, this update was requested without meshing.
|
||||||
mesh: Option<MeshWorkerResponseMesh>,
|
mesh: Option<MeshWorkerResponseMesh>,
|
||||||
started_tick: u64,
|
started_tick: u64,
|
||||||
@ -244,8 +255,12 @@ fn mesh_worker(
|
|||||||
mesh = None;
|
mesh = None;
|
||||||
(&**light_map, &**glow_map)
|
(&**light_map, &**glow_map)
|
||||||
} else {
|
} else {
|
||||||
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) =
|
let (
|
||||||
generate_mesh(
|
opaque_mesh,
|
||||||
|
fluid_mesh,
|
||||||
|
_shadow_mesh,
|
||||||
|
(bounds, col_lights_info, light_map, glow_map, alt_indices),
|
||||||
|
) = generate_mesh(
|
||||||
&volume,
|
&volume,
|
||||||
(
|
(
|
||||||
range,
|
range,
|
||||||
@ -261,6 +276,7 @@ fn mesh_worker(
|
|||||||
col_lights_info,
|
col_lights_info,
|
||||||
light_map,
|
light_map,
|
||||||
glow_map,
|
glow_map,
|
||||||
|
alt_indices,
|
||||||
});
|
});
|
||||||
// Pointer juggling so borrows work out.
|
// Pointer juggling so borrows work out.
|
||||||
let mesh = mesh.as_ref().unwrap();
|
let mesh = mesh.as_ref().unwrap();
|
||||||
@ -272,7 +288,19 @@ fn mesh_worker(
|
|||||||
// Extract sprite locations from volume
|
// Extract sprite locations from volume
|
||||||
sprite_instances: {
|
sprite_instances: {
|
||||||
prof_span!("extract sprite_instances");
|
prof_span!("extract sprite_instances");
|
||||||
let mut instances = [(); SPRITE_LOD_LEVELS].map(|()| Vec::new());
|
let mut instances = [(); SPRITE_LOD_LEVELS].map(|()| {
|
||||||
|
(
|
||||||
|
Vec::new(), // Deep
|
||||||
|
Vec::new(), // Shallow
|
||||||
|
Vec::new(), // Surface
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let (underground_alt, deep_alt) = volume
|
||||||
|
.get_key(volume.pos_key((range.min + range.max) / 2))
|
||||||
|
.map_or((0.0, 0.0), |c| {
|
||||||
|
(c.meta().alt() - SHALLOW_ALT, c.meta().alt() - DEEP_ALT)
|
||||||
|
});
|
||||||
|
|
||||||
for x in 0..TerrainChunk::RECT_SIZE.x as i32 {
|
for x in 0..TerrainChunk::RECT_SIZE.x as i32 {
|
||||||
for y in 0..TerrainChunk::RECT_SIZE.y as i32 {
|
for y in 0..TerrainChunk::RECT_SIZE.y as i32 {
|
||||||
@ -304,7 +332,7 @@ fn mesh_worker(
|
|||||||
let light = light_map(wpos);
|
let light = light_map(wpos);
|
||||||
let glow = glow_map(wpos);
|
let glow = glow_map(wpos);
|
||||||
|
|
||||||
for (lod_level, sprite_data) in
|
for ((deep_level, shallow_level, surface_level), sprite_data) in
|
||||||
instances.iter_mut().zip(&sprite_data[&key])
|
instances.iter_mut().zip(&sprite_data[&key])
|
||||||
{
|
{
|
||||||
let mat = Mat4::identity()
|
let mat = Mat4::identity()
|
||||||
@ -332,7 +360,13 @@ fn mesh_worker(
|
|||||||
page,
|
page,
|
||||||
matches!(sprite, SpriteKind::Door),
|
matches!(sprite, SpriteKind::Door),
|
||||||
);
|
);
|
||||||
lod_level.push(instance);
|
if (wpos.z as f32) < deep_alt {
|
||||||
|
deep_level.push(instance);
|
||||||
|
} else if wpos.z as f32 > underground_alt {
|
||||||
|
surface_level.push(instance);
|
||||||
|
} else {
|
||||||
|
shallow_level.push(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,7 +374,21 @@ fn mesh_worker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instances
|
instances.map(|(deep_level, shallow_level, surface_level)| {
|
||||||
|
let deep_end = deep_level.len();
|
||||||
|
let alt_indices = AltIndices {
|
||||||
|
deep_end,
|
||||||
|
underground_end: deep_end + shallow_level.len(),
|
||||||
|
};
|
||||||
|
(
|
||||||
|
deep_level
|
||||||
|
.into_iter()
|
||||||
|
.chain(shallow_level.into_iter())
|
||||||
|
.chain(surface_level.into_iter())
|
||||||
|
.collect(),
|
||||||
|
alt_indices,
|
||||||
|
)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
mesh,
|
mesh,
|
||||||
blocks_of_interest,
|
blocks_of_interest,
|
||||||
@ -1141,10 +1189,14 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
Some(todo) if response.started_tick <= todo.started_tick => {
|
Some(todo) if response.started_tick <= todo.started_tick => {
|
||||||
let started_tick = todo.started_tick;
|
let started_tick = todo.started_tick;
|
||||||
|
|
||||||
let sprite_instances = response.sprite_instances.map(|instances| {
|
let sprite_instances =
|
||||||
|
response.sprite_instances.map(|(instances, alt_indices)| {
|
||||||
|
(
|
||||||
renderer
|
renderer
|
||||||
.create_instances(&instances)
|
.create_instances(&instances)
|
||||||
.expect("Failed to upload chunk sprite instances to the GPU!")
|
.expect("Failed to upload chunk sprite instances to the GPU!"),
|
||||||
|
alt_indices,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(mesh) = response.mesh {
|
if let Some(mesh) = response.mesh {
|
||||||
@ -1226,6 +1278,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
blocks_of_interest: response.blocks_of_interest,
|
blocks_of_interest: response.blocks_of_interest,
|
||||||
z_bounds: mesh.z_bounds,
|
z_bounds: mesh.z_bounds,
|
||||||
frustum_last_plane_index: 0,
|
frustum_last_plane_index: 0,
|
||||||
|
alt_indices: mesh.alt_indices,
|
||||||
});
|
});
|
||||||
} else if let Some(chunk) = self.chunks.get_mut(&response.pos) {
|
} else if let Some(chunk) = self.chunks.get_mut(&response.pos) {
|
||||||
// There was an update that didn't require a remesh (probably related to
|
// There was an update that didn't require a remesh (probably related to
|
||||||
@ -1576,7 +1629,12 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>, focus_pos: Vec3<f32>) {
|
pub fn render<'a>(
|
||||||
|
&'a self,
|
||||||
|
drawer: &mut FirstPassDrawer<'a>,
|
||||||
|
focus_pos: Vec3<f32>,
|
||||||
|
is_underground: bool,
|
||||||
|
) {
|
||||||
span!(_guard, "render", "Terrain::render");
|
span!(_guard, "render", "Terrain::render");
|
||||||
let mut drawer = drawer.draw_terrain();
|
let mut drawer = drawer.draw_terrain();
|
||||||
|
|
||||||
@ -1595,9 +1653,11 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
chunk
|
chunk
|
||||||
.opaque_model
|
.opaque_model
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|model| (model, &chunk.col_lights, &chunk.locals))
|
.map(|model| (model, &chunk.col_lights, &chunk.locals, &chunk.alt_indices))
|
||||||
})
|
})
|
||||||
.for_each(|(model, col_lights, locals)| drawer.draw(model, col_lights, locals));
|
.for_each(|(model, col_lights, locals, alt_indices)| {
|
||||||
|
drawer.draw(model, col_lights, locals, alt_indices, is_underground)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_translucent<'a>(
|
pub fn render_translucent<'a>(
|
||||||
@ -1606,6 +1666,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
focus_pos: Vec3<f32>,
|
focus_pos: Vec3<f32>,
|
||||||
cam_pos: Vec3<f32>,
|
cam_pos: Vec3<f32>,
|
||||||
sprite_render_distance: f32,
|
sprite_render_distance: f32,
|
||||||
|
is_underground: bool,
|
||||||
) {
|
) {
|
||||||
span!(_guard, "render_translucent", "Terrain::render_translucent");
|
span!(_guard, "render_translucent", "Terrain::render_translucent");
|
||||||
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
|
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
|
||||||
@ -1636,7 +1697,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
.filter(|(_, c)| c.visible.is_visible())
|
.filter(|(_, c)| c.visible.is_visible())
|
||||||
.for_each(|(pos, chunk)| {
|
.for_each(|(pos, chunk)| {
|
||||||
// Skip chunk if it has no sprites
|
// Skip chunk if it has no sprites
|
||||||
if chunk.sprite_instances[0].count() == 0 {
|
if chunk.sprite_instances[0].0.count() == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1662,7 +1723,12 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
4
|
4
|
||||||
};
|
};
|
||||||
|
|
||||||
sprite_drawer.draw(&chunk.locals, &chunk.sprite_instances[lod_level]);
|
sprite_drawer.draw(
|
||||||
|
&chunk.locals,
|
||||||
|
&chunk.sprite_instances[lod_level].0,
|
||||||
|
&chunk.sprite_instances[lod_level].1,
|
||||||
|
is_underground,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
drop(sprite_drawer);
|
drop(sprite_drawer);
|
||||||
|
Loading…
Reference in New Issue
Block a user