Create (segment, offset) just once per figure.

This commit is contained in:
Joshua Yanovski 2020-08-28 19:10:10 +02:00
parent 7e6975d881
commit 4eeb131f4b
8 changed files with 389 additions and 1052 deletions

View File

@ -273,3 +273,8 @@ impl<'a, T: ReadVol> Iterator for DefaultVolIterator<'a, T> {
None None
} }
} }
impl<'b, T: ReadVol> ReadVol for &'b T {
#[inline(always)]
fn get<'a>(&'a self, pos: Vec3<i32>) -> Result<&'a Self::Vox, Self::Error> { (*self).get(pos) }
}

View File

@ -59,6 +59,14 @@ impl<V: Vox, M, A: Access> SizedVol for Dyna<V, M, A> {
fn upper_bound(&self) -> Vec3<i32> { self.sz.map(|e| e as i32) } fn upper_bound(&self) -> Vec3<i32> { self.sz.map(|e| e as i32) }
} }
impl<'a, V: Vox, M, A: Access> SizedVol for &'a Dyna<V, M, A> {
#[inline(always)]
fn lower_bound(&self) -> Vec3<i32> { (*self).lower_bound() }
#[inline(always)]
fn upper_bound(&self) -> Vec3<i32> { (*self).upper_bound() }
}
impl<V: Vox, M, A: Access> ReadVol for Dyna<V, M, A> { impl<V: Vox, M, A: Access> ReadVol for Dyna<V, M, A> {
#[inline(always)] #[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaError> { fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaError> {

View File

@ -13,7 +13,6 @@ use common::{
figure::Cell, figure::Cell,
vol::{BaseVol, ReadVol, SizedVol, Vox}, vol::{BaseVol, ReadVol, SizedVol, Vox},
}; };
use core::ops::Range;
use vek::*; use vek::*;
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex; type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
@ -28,32 +27,26 @@ where
* &'a V: BaseVol<Vox=Cell>, */ * &'a V: BaseVol<Vox=Cell>, */
{ {
type Pipeline = TerrainPipeline; type Pipeline = TerrainPipeline;
/// NOTE: The result provides the (roughly) computed bounds for the model, type Result = math::Aabb<f32>;
/// and the vertex range meshed for this model; we return this instead
/// of the full opaque mesh so we can avoid allocating a separate mesh
/// for each bone.
///
/// Later, we can iterate through the bone array and correctly assign bone
/// ids to all vertices in range for each segment.
///
/// FIXME: A refactor of the figure cache to not just return an array of
/// models (thus allowing us to knoe the bone index ahead of time) would
/// avoid needing per-bone information at all.
type Result = (math::Aabb<f32>, Range<usize>);
type ShadowPipeline = ShadowPipeline; type ShadowPipeline = ShadowPipeline;
/// NOTE: bone_idx must be in [0, 15] (may be bumped to [0, 31] at some
/// point).
type Supplement = ( type Supplement = (
&'b mut GreedyMesh<'a>, &'b mut GreedyMesh<'a>,
&'b mut Mesh<Self::Pipeline>, &'b mut Mesh<Self::Pipeline>,
Vec3<f32>, Vec3<f32>,
Vec3<f32>, Vec3<f32>,
u8,
); );
type TranslucentPipeline = FigurePipeline; type TranslucentPipeline = FigurePipeline;
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
fn generate_mesh( fn generate_mesh(
self, self,
(greedy, opaque_mesh, offs, scale): Self::Supplement, (greedy, opaque_mesh, offs, scale, bone_idx): Self::Supplement,
) -> MeshGen<FigurePipeline, &'b mut GreedyMesh<'a>, Self> { ) -> MeshGen<FigurePipeline, &'b mut GreedyMesh<'a>, Self> {
assert!(bone_idx <= 15, "Bone index for figures must be in [0, 15]");
let max_size = greedy.max_size(); let max_size = greedy.max_size();
// NOTE: Required because we steal two bits from the normal in the shadow uint // NOTE: Required because we steal two bits from the normal in the shadow uint
// in order to store the bone index. The two bits are instead taken out // in order to store the bone index. The two bits are instead taken out
@ -98,10 +91,9 @@ where
}) })
}; };
let create_opaque = |atlas_pos, pos, norm| { let create_opaque = |atlas_pos, pos, norm| {
TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, 0) TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, bone_idx)
}; };
let start = opaque_mesh.vertices().len();
greedy.push(GreedyConfig { greedy.push(GreedyConfig {
data: self, data: self,
draw_delta, draw_delta,
@ -129,14 +121,8 @@ where
max: math::Vec3::from((upper_bound.as_::<f32>() + offs) * scale), max: math::Vec3::from((upper_bound.as_::<f32>() + offs) * scale),
} }
.made_valid(); .made_valid();
let vertex_range = start..opaque_mesh.vertices().len();
( (Mesh::new(), Mesh::new(), Mesh::new(), bounds)
Mesh::new(),
Mesh::new(),
Mesh::new(),
(bounds, vertex_range),
)
} }
} }

View File

@ -3,7 +3,6 @@ use super::{
shadow, Globals, Light, Shadow, shadow, Globals, Light, Shadow,
}; };
use crate::mesh::greedy::GreedyMesh; use crate::mesh::greedy::GreedyMesh;
use core::ops::Range;
use gfx::{ use gfx::{
self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline,
gfx_pipeline_inner, state::ColorMask, gfx_pipeline_inner, state::ColorMask,
@ -122,4 +121,4 @@ impl FigureModel {
} }
} }
pub type BoneMeshes = (Mesh<TerrainPipeline>, (anim::vek::Aabb<f32>, Range<usize>)); pub type BoneMeshes = (Mesh<TerrainPipeline>, anim::vek::Aabb<f32>);

View File

@ -105,11 +105,6 @@ impl Vertex {
{ {
[col.r, col.g, col.b, light] [col.r, col.g, col.b, light]
} }
/// Set the bone_idx for an existing figure vertex.
pub fn set_bone_idx(&mut self, bone_idx: u8) {
self.pos_norm = (self.pos_norm & !(0xF << 27)) | ((bone_idx as u32 & 0xF) << 27);
}
} }
impl Locals { impl Locals {

View File

@ -367,7 +367,11 @@ where
let slot_ = Arc::clone(&slot); let slot_ = Arc::clone(&slot);
thread_pool.execute(move || { thread_pool.execute(move || {
// First, load all the base vertex data.
let manifests = &*manifests; let manifests = &*manifests;
let meshes = <Skel::Body as BodySpec>::bone_meshes(&key, &*manifests);
// Then, set up meshing context.
let mut greedy = FigureModel::make_greedy(); let mut greedy = FigureModel::make_greedy();
let mut opaque = Mesh::<TerrainPipeline>::new(); let mut opaque = Mesh::<TerrainPipeline>::new();
// Choose the most conservative bounds for any LOD model. // Choose the most conservative bounds for any LOD model.
@ -382,31 +386,21 @@ where
let mut make_model = |generate_mesh: for<'a, 'b> fn( let mut make_model = |generate_mesh: for<'a, 'b> fn(
&mut GreedyMesh<'a>, &mut GreedyMesh<'a>,
&'b mut _, &'b mut _,
&'a _,
_, _,
_, _,
) )
-> _| { -> _| {
let vertex_start = opaque.vertices().len(); let vertex_start = opaque.vertices().len();
let meshes = <Skel::Body as BodySpec>::bone_meshes(
&key,
&*manifests,
|segment, offset| {
generate_mesh(&mut greedy, &mut opaque, segment, offset)
},
);
meshes meshes
.iter() .iter()
.enumerate() .enumerate()
// NOTE: Cast to u8 is safe because i <= 16. // NOTE: Cast to u8 is safe because i < 16.
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i as u8, bm.clone()))) .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i as u8, bm)))
.for_each(|(i, (_opaque_mesh, (bounds, vertex_range)))| { .for_each(|(i, (segment, offset))| {
// Update the bone index for all vertices that belong to this // Generate this mesh.
// model. let (_opaque_mesh, bounds) =
opaque generate_mesh(&mut greedy, &mut opaque, segment, *offset, i);
.iter_mut(vertex_range)
.for_each(|vert| {
vert.set_bone_idx(i);
});
// Update the figure bounds to the largest granularity seen so far // Update the figure bounds to the largest granularity seen so far
// (NOTE: this is more than a little imperfect). // (NOTE: this is more than a little imperfect).
@ -442,13 +436,14 @@ where
fn generate_mesh<'a>( fn generate_mesh<'a>(
greedy: &mut GreedyMesh<'a>, greedy: &mut GreedyMesh<'a>,
opaque_mesh: &mut Mesh<TerrainPipeline>, opaque_mesh: &mut Mesh<TerrainPipeline>,
segment: Segment, segment: &'a Segment,
offset: Vec3<f32>, offset: Vec3<f32>,
bone_idx: u8,
) -> BoneMeshes { ) -> BoneMeshes {
let (opaque, _, _, bounds) = let (opaque, _, _, bounds) =
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh( Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
segment, segment,
(greedy, opaque_mesh, offset, Vec3::one()), (greedy, opaque_mesh, offset, Vec3::one(), bone_idx),
); );
(opaque, bounds) (opaque, bounds)
} }
@ -456,8 +451,9 @@ where
fn generate_mesh_lod_mid<'a>( fn generate_mesh_lod_mid<'a>(
greedy: &mut GreedyMesh<'a>, greedy: &mut GreedyMesh<'a>,
opaque_mesh: &mut Mesh<TerrainPipeline>, opaque_mesh: &mut Mesh<TerrainPipeline>,
segment: Segment, segment: &'a Segment,
offset: Vec3<f32>, offset: Vec3<f32>,
bone_idx: u8,
) -> BoneMeshes { ) -> BoneMeshes {
let lod_scale = 0.6; let lod_scale = 0.6;
let (opaque, _, _, bounds) = let (opaque, _, _, bounds) =
@ -468,6 +464,7 @@ where
opaque_mesh, opaque_mesh,
offset * lod_scale, offset * lod_scale,
Vec3::one() / lod_scale, Vec3::one() / lod_scale,
bone_idx,
), ),
); );
(opaque, bounds) (opaque, bounds)
@ -476,8 +473,9 @@ where
fn generate_mesh_lod_low<'a>( fn generate_mesh_lod_low<'a>(
greedy: &mut GreedyMesh<'a>, greedy: &mut GreedyMesh<'a>,
opaque_mesh: &mut Mesh<TerrainPipeline>, opaque_mesh: &mut Mesh<TerrainPipeline>,
segment: Segment, segment: &'a Segment,
offset: Vec3<f32>, offset: Vec3<f32>,
bone_idx: u8,
) -> BoneMeshes { ) -> BoneMeshes {
let lod_scale = 0.3; let lod_scale = 0.3;
let (opaque, _, _, bounds) = let (opaque, _, _, bounds) =
@ -488,6 +486,7 @@ where
opaque_mesh, opaque_mesh,
offset * lod_scale, offset * lod_scale,
Vec3::one() / lod_scale, Vec3::one() / lod_scale,
bone_idx,
), ),
); );
(opaque, bounds) (opaque, bounds)

File diff suppressed because it is too large Load Diff

View File

@ -50,11 +50,12 @@ fn generate_mesh<'a>(
mesh: &mut Mesh<TerrainPipeline>, mesh: &mut Mesh<TerrainPipeline>,
segment: Segment, segment: Segment,
offset: Vec3<f32>, offset: Vec3<f32>,
bone_idx: u8,
) -> BoneMeshes { ) -> BoneMeshes {
let (opaque, _, /* shadow */ _, bounds) = let (opaque, _, /* shadow */ _, bounds) =
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh( Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
segment, segment,
(greedy, mesh, offset, Vec3::one()), (greedy, mesh, offset, Vec3::one(), bone_idx),
); );
(opaque /* , shadow */, bounds) (opaque /* , shadow */, bounds)
} }
@ -154,16 +155,14 @@ impl Scene {
let mut state = FigureState::new(renderer, FixtureSkeleton::default()); let mut state = FigureState::new(renderer, FixtureSkeleton::default());
let mut greedy = FigureModel::make_greedy(); let mut greedy = FigureModel::make_greedy();
let mut opaque_mesh = Mesh::new(); let mut opaque_mesh = Mesh::new();
let (_opaque_mesh, (bounds, range)) = load_mesh( let (segment, offset) = load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0));
specifier, let (_opaque_mesh, bounds) =
Vec3::new(-55.0, -49.5, -2.0), generate_mesh(&mut greedy, &mut opaque_mesh, segment, offset, 0);
|segment, offset| generate_mesh(&mut greedy, &mut opaque_mesh, segment, offset),
);
// NOTE: Since MagicaVoxel sizes are limited to 256 × 256 × 256, and there are // NOTE: Since MagicaVoxel sizes are limited to 256 × 256 × 256, and there are
// at most 3 meshed vertices per unique vertex, we know the // at most 3 meshed vertices per unique vertex, we know the
// total size is bounded by 2^24 * 3 * 1.5 which is bounded by // total size is bounded by 2^24 * 3 * 1.5 which is bounded by
// 2^27, which fits in a u32. // 2^27, which fits in a u32.
let range = range.start as u32..range.end as u32; let range = 0..opaque_mesh.vertices().len() as u32;
let model = col_lights let model = col_lights
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]) .create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range])
.unwrap(); .unwrap();