Addressed review comments

This commit is contained in:
Sam 2022-02-27 00:15:10 -05:00
parent 5a60562eee
commit 0a0fffd5ed
7 changed files with 147 additions and 103 deletions

View File

@ -49,8 +49,8 @@ pub use self::{
stunned::StunnedAnimation, swim::SwimAnimation, swimwield::SwimWieldAnimation,
talk::TalkAnimation, wallrun::WallrunAnimation, wield::WieldAnimation,
};
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
use common::comp::{self, tool::ToolKind};
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource};
use common::comp;
use core::{convert::TryFrom, f32::consts::PI};
pub type Body = comp::humanoid::Body;
@ -152,37 +152,6 @@ impl Skeleton for CharacterSkeleton {
// FIXME: Should this be control_l_mat?
make_bone(control_mat * hand_l_mat * Mat4::<f32>::from(self.hold)),
];
let weapon_offsets = |tool| {
let lengths = match tool {
Some(ToolKind::Sword) => (0.0, 29.25),
Some(ToolKind::Axe) => (10.0, 19.25),
Some(ToolKind::Hammer) => (10.0, 19.25),
Some(ToolKind::Staff) => (10.0, 19.25),
Some(ToolKind::Sceptre) => (10.0, 19.25),
_ => (0.0, 0.0),
};
(
Vec4::new(0.0, 0.0, lengths.0, 1.0),
Vec4::new(0.0, 0.0, lengths.1, 1.0),
)
};
// Offsets
const GLIDER_VERT: f32 = 5.0;
const GLIDER_HORIZ: f32 = 15.0;
// Trail width
const GLIDER_WIDTH: f32 = 1.0;
let glider_offsets_0 = |_| {
(
Vec4::new(GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(GLIDER_HORIZ + GLIDER_WIDTH, 0.0, GLIDER_VERT, 1.0),
)
};
let glider_offsets_1 = |_| {
(
Vec4::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT, 1.0),
)
};
let weapon_trails = self.main_weapon_trail || self.off_weapon_trail;
Offsets {
lantern: Some((lantern_mat * Vec4::new(0.0, 0.5, -6.0, 1.0)).xyz()),
@ -195,15 +164,18 @@ impl Skeleton for CharacterSkeleton {
..Default::default()
},
primary_trail_mat: if weapon_trails {
self.main_weapon_trail.then_some((main_mat, weapon_offsets))
self.main_weapon_trail
.then_some((main_mat, TrailSource::Weapon))
} else {
self.glider_trails.then_some((glider_mat, glider_offsets_0))
self.glider_trails
.then_some((glider_mat, TrailSource::GliderLeft))
},
secondary_trail_mat: if weapon_trails {
self.off_weapon_trail
.then_some((second_mat, weapon_offsets))
.then_some((second_mat, TrailSource::Weapon))
} else {
self.glider_trails.then_some((glider_mat, glider_offsets_1))
self.glider_trails
.then_some((glider_mat, TrailSource::GliderRight))
},
}
}

View File

@ -104,8 +104,50 @@ pub fn init() { lazy_static::initialize(&LIB); }
pub struct Offsets {
pub lantern: Option<Vec3<f32>>,
pub mount_bone: Transform<f32, f32, f32>,
pub primary_trail_mat: Option<(Mat4<f32>, fn(Option<ToolKind>) -> (Vec4<f32>, Vec4<f32>))>,
pub secondary_trail_mat: Option<(Mat4<f32>, fn(Option<ToolKind>) -> (Vec4<f32>, Vec4<f32>))>,
pub primary_trail_mat: Option<(Mat4<f32>, TrailSource)>,
pub secondary_trail_mat: Option<(Mat4<f32>, TrailSource)>,
}
#[derive(Clone, Copy)]
pub enum TrailSource {
Weapon,
GliderLeft,
GliderRight,
}
impl TrailSource {
pub fn relative_offsets(&self, tool: Option<ToolKind>) -> (Vec4<f32>, Vec4<f32>) {
// Offsets
const GLIDER_VERT: f32 = 5.0;
const GLIDER_HORIZ: f32 = 15.0;
// Trail width
const GLIDER_WIDTH: f32 = 1.0;
match self {
Self::Weapon => {
let lengths = match tool {
Some(ToolKind::Sword) => (0.0, 29.25),
Some(ToolKind::Axe) => (10.0, 19.25),
Some(ToolKind::Hammer) => (10.0, 19.25),
Some(ToolKind::Staff) => (10.0, 19.25),
Some(ToolKind::Sceptre) => (10.0, 19.25),
_ => (0.0, 0.0),
};
(
Vec4::new(0.0, 0.0, lengths.0, 1.0),
Vec4::new(0.0, 0.0, lengths.1, 1.0),
)
},
Self::GliderLeft => (
Vec4::new(GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(GLIDER_HORIZ + GLIDER_WIDTH, 0.0, GLIDER_VERT, 1.0),
),
Self::GliderRight => (
Vec4::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
Vec4::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT, 1.0),
),
}
}
}
pub trait Skeleton: Send + Sync + 'static {

View File

@ -606,6 +606,7 @@ impl<'frame> Drop for Drawer<'frame> {
}
// Shadow pass
#[must_use]
pub struct ShadowPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
@ -636,6 +637,7 @@ impl<'pass> ShadowPassDrawer<'pass> {
}
}
#[must_use]
pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
@ -653,6 +655,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
}
}
#[must_use]
pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
@ -671,6 +674,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
}
// First pass
#[must_use]
pub struct FirstPassDrawer<'pass> {
pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
@ -769,6 +773,7 @@ impl<'pass> FirstPassDrawer<'pass> {
}
}
#[must_use]
pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
shadows: &'pass ShadowTexturesBindGroup,
@ -794,6 +799,8 @@ impl<'pass_ref, 'pass: 'pass_ref> Drop for DebugDrawer<'pass_ref, 'pass> {
.set_bind_group(1, &self.shadows.bind_group, &[]);
}
}
#[must_use]
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
@ -815,6 +822,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
}
}
#[must_use]
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
col_lights: Option<&'pass_ref Arc<ColLights<terrain::Locals>>>,
@ -845,6 +853,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
}
}
#[must_use]
pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
@ -866,18 +875,7 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
}
}
pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
self.render_pass.set_vertex_buffer(0, submodel.buf());
self.render_pass
.draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
}
}
#[must_use]
pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
globals: &'pass GlobalsBindGroup,
@ -910,6 +908,7 @@ impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> {
}
}
#[must_use]
pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
@ -928,6 +927,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
}
// Second pass: clouds
#[must_use]
pub struct SecondPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
@ -943,17 +943,33 @@ impl<'pass> SecondPassDrawer<'pass> {
self.render_pass.draw(0..3, 0..1);
}
pub fn draw_trails(&mut self) -> TrailDrawer<'_, 'pass> {
pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> {
let mut render_pass = self.render_pass.scope("trails", self.borrow.device);
render_pass.set_pipeline(&self.pipelines.trail.pipeline);
set_quad_index_buffer::<trail::Vertex>(&mut render_pass, self.borrow);
TrailDrawer { render_pass }
render_pass.set_bind_group(1, &self.borrow.shadow?.bind.bind_group, &[]);
Some(TrailDrawer { render_pass })
}
}
#[must_use]
pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
self.render_pass.set_vertex_buffer(0, submodel.buf());
self.render_pass
.draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
}
}
/// Third pass: postprocess + ui
#[must_use]
pub struct ThirdPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
@ -986,10 +1002,12 @@ impl<'pass> ThirdPassDrawer<'pass> {
}
}
#[must_use]
pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
#[must_use]
pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}

View File

@ -419,6 +419,7 @@ fn create_interface_pipelines(
fn create_ingame_and_shadow_pipelines(
needs: PipelineNeeds,
pool: &rayon::ThreadPool,
// TODO: Reduce the boilerplate in this file
tasks: [Task; 15],
) -> IngameAndShadowPipelines {
prof_span!(_guard, "create_ingame_and_shadow_pipelines");
@ -723,8 +724,12 @@ fn create_ingame_and_shadow_pipelines(
let j1 = || pool.join(create_debug, || pool.join(create_skybox, create_figure));
let j2 = || pool.join(create_terrain, || pool.join(create_fluid, create_bloom));
let j3 = || pool.join(create_sprite, || pool.join(create_particle, create_trail));
let j4 = || pool.join(create_lod_terrain, create_clouds);
let j3 = || pool.join(create_sprite, create_particle);
let j4 = || {
pool.join(create_lod_terrain, || {
pool.join(create_clouds, create_trail)
})
};
let j5 = || pool.join(create_postprocess, create_point_shadow);
let j6 = || {
pool.join(
@ -737,7 +742,7 @@ fn create_ingame_and_shadow_pipelines(
let (
(
((debug, (skybox, figure)), (terrain, (fluid, bloom))),
((sprite, (particle, trail)), (lod_terrain, clouds)),
((sprite, particle), (lod_terrain, (clouds, trail))),
),
((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)),
) = pool.join(

View File

@ -6446,18 +6446,15 @@ impl<S: Skeleton> FigureState<S> {
// Handle weapon trails
fn handle_weapon_trails(
trail_mgr: &mut TrailMgr,
new_weapon_trail_mat: Option<(
anim::vek::Mat4<f32>,
fn(Option<ToolKind>) -> (anim::vek::Vec4<f32>, anim::vek::Vec4<f32>),
)>,
new_weapon_trail_mat: Option<(anim::vek::Mat4<f32>, anim::TrailSource)>,
old_abs_trail_points: &mut Option<(anim::vek::Vec3<f32>, anim::vek::Vec3<f32>)>,
entity: EcsEntity,
is_main_weapon: bool,
pos: anim::vek::Vec3<f32>,
tools: (Option<ToolKind>, Option<ToolKind>),
tool: Option<ToolKind>,
) {
let weapon_offsets = new_weapon_trail_mat.map(|(mat, offsets)| {
let (trail_start, trail_end) = offsets(tools.0);
let weapon_offsets = new_weapon_trail_mat.map(|(mat, trail)| {
let (trail_start, trail_end) = trail.relative_offsets(tool);
((mat * trail_start).xyz(), (mat * trail_end).xyz())
});
let new_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos));
@ -6482,7 +6479,7 @@ impl<S: Skeleton> FigureState<S> {
*entity,
true,
*pos,
*tools,
tools.0,
);
handle_weapon_trails(
trail_mgr,
@ -6491,7 +6488,7 @@ impl<S: Skeleton> FigureState<S> {
*entity,
false,
*pos,
*tools,
tools.1,
);
}

View File

@ -23,7 +23,7 @@ pub struct TrailMgr {
offset: usize,
/// Dynamic model to upload to GPU
dynamic_model: DynamicModel<TrailVertex>,
dynamic_model: Option<DynamicModel<TrailVertex>>,
/// Used to create sub model from dynamic model
model_len: u32,
@ -33,12 +33,12 @@ const TRAIL_DYNAMIC_MODEL_SIZE: usize = 15;
const TRAIL_SHRINKAGE: f32 = 0.8;
impl TrailMgr {
pub fn new(renderer: &mut Renderer) -> Self {
pub fn new(_renderer: &mut Renderer) -> Self {
Self {
entity_meshes: HashMap::new(),
pos_cache: HashMap::new(),
offset: 0,
dynamic_model: renderer.create_dynamic_model(0),
dynamic_model: None,
model_len: 0,
}
}
@ -118,12 +118,12 @@ impl TrailMgr {
// Clear meshes for entities that only have zero quads in mesh
self.entity_meshes
.retain(|_, (mesh, _)| mesh.iter().any(|vert| *vert != TrailVertex::zero()));
// .retain(|_, (_mesh, last_updated)| *last_updated == self.offset);
.retain(|_, (_mesh, last_updated)| *last_updated != self.offset);
// TODO: as an optimization we can keep this big mesh around between frames and
// write directly to it for each entity. Create big mesh from
// currently existing meshes that is used to update dynamic model
// write directly to it for each entity.
// Create big mesh from currently existing meshes that is used to update dynamic
// model
let mut big_mesh = Mesh::new();
self.entity_meshes
.values()
@ -139,24 +139,29 @@ impl TrailMgr {
// If dynamic model too small, resize, with room for 10 additional entities to
// avoid needing to resize frequently
if self.dynamic_model.len() < big_mesh.len() {
self.dynamic_model = renderer
.create_dynamic_model(big_mesh.len() + TRAIL_DYNAMIC_MODEL_SIZE * 4 * 10);
};
renderer.update_model(&self.dynamic_model, &big_mesh, 0);
if self.dynamic_model.as_ref().map_or(0, |model| model.len()) < big_mesh.len() {
self.dynamic_model = Some(
renderer
.create_dynamic_model(big_mesh.len() + TRAIL_DYNAMIC_MODEL_SIZE * 4 * 10),
);
}
if let Some(dynamic_model) = &self.dynamic_model {
renderer.update_model(dynamic_model, &big_mesh, 0);
}
self.model_len = big_mesh.len() as u32;
} else {
self.entity_meshes.clear();
// Clear dynamic model to free memory
self.dynamic_model = renderer.create_dynamic_model(0);
self.dynamic_model = None;
}
}
pub fn render<'a>(&'a self, drawer: &mut TrailDrawer<'_, 'a>, scene_data: &SceneData) {
span!(_guard, "render", "TrailMgr::render");
if scene_data.weapon_trails_enabled {
// drawer.draw(&self.dynamic_model, self.model_len);
drawer.draw(self.dynamic_model.submodel(0..self.model_len))
if let Some(dynamic_model) = &self.dynamic_model {
drawer.draw(dynamic_model.submodel(0..self.model_len))
}
}
}
@ -172,6 +177,7 @@ impl TrailMgr {
&mut self
.entity_meshes
.entry(key)
.and_modify(|(_mesh, offset)| *offset = self.offset)
.or_insert((Self::default_trail_mesh(), self.offset))
.0
}

View File

@ -1528,30 +1528,30 @@ impl PlayState for SessionState {
fn render<'a>(&'a self, drawer: &mut Drawer<'a>, settings: &Settings) {
span!(_guard, "render", "<Session as PlayState>::render");
let client = self.client.borrow();
let scene_data = SceneData {
client: &client,
state: client.state(),
player_entity: client.entity(),
// Only highlight if interactable
target_entity: self.interactable.and_then(Interactable::entity),
loaded_distance: client.loaded_distance(),
view_distance: client.view_distance().unwrap_or(1),
tick: client.get_tick(),
gamma: settings.graphics.gamma,
exposure: settings.graphics.exposure,
ambiance: settings.graphics.ambiance,
mouse_smoothing: settings.gameplay.smooth_pan_enable,
sprite_render_distance: settings.graphics.sprite_render_distance as f32,
figure_lod_render_distance: settings.graphics.figure_lod_render_distance as f32,
particles_enabled: settings.graphics.particles_enabled,
weapon_trails_enabled: settings.graphics.weapon_trails_enabled,
is_aiming: self.is_aiming,
};
// Render world
{
let client = self.client.borrow();
let scene_data = SceneData {
client: &client,
state: client.state(),
player_entity: client.entity(),
// Only highlight if interactable
target_entity: self.interactable.and_then(Interactable::entity),
loaded_distance: client.loaded_distance(),
view_distance: client.view_distance().unwrap_or(1),
tick: client.get_tick(),
gamma: settings.graphics.gamma,
exposure: settings.graphics.exposure,
ambiance: settings.graphics.ambiance,
mouse_smoothing: settings.gameplay.smooth_pan_enable,
sprite_render_distance: settings.graphics.sprite_render_distance as f32,
figure_lod_render_distance: settings.graphics.figure_lod_render_distance as f32,
particles_enabled: settings.graphics.particles_enabled,
weapon_trails_enabled: settings.graphics.weapon_trails_enabled,
is_aiming: self.is_aiming,
};
self.scene.render(
drawer,
client.state(),
@ -1570,7 +1570,11 @@ impl PlayState for SessionState {
// Trails
{
prof_span!("trails");
second_pass.draw_trails();
if let Some(mut trail_drawer) = second_pass.draw_trails() {
self.scene
.trail_mgr()
.render(&mut trail_drawer, &scene_data);
}
}
}
// Bloom (call does nothing if bloom is off)