Addressed review comments

This commit is contained in:
Sam 2022-02-26 13:18:34 -05:00
parent ce70c512e2
commit 5a60562eee
13 changed files with 125 additions and 113 deletions

View File

@ -78,6 +78,8 @@ void main() {
vec3 emitted_light, reflected_light;
// TODO: Look into using the same light parameter that is used for figures
// Comment on this method copy-pasted from particle shader:
// This is a bit of a hack. Because we can't find the volumetric lighting of each particle (they don't talk to the
// CPU) we need to some how find an approximation of how much the sun is blocked. We do this by fading out the sun
// as the particle moves underground. This isn't perfect, but it does at least mean that particles don't look like

View File

@ -46,6 +46,7 @@ impl Animation for AlphaAnimation {
next.second.orientation = Quaternion::rotation_z(0.0);
next.torso.position = Vec3::new(0.0, 0.0, 1.1);
next.torso.orientation = Quaternion::rotation_z(0.0);
if matches!(
stage_section,
Some(StageSection::Action | StageSection::Recover)

View File

@ -54,6 +54,7 @@ impl Animation for ChargeswingAnimation {
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4), 0.0, 1.0),
_ => (0.0, 0.0, 0.0, 0.0, 0.0),
};
if matches!(
stage_section,
Some(StageSection::Charge | StageSection::Action | StageSection::Recover)

View File

@ -42,6 +42,7 @@ impl Animation for ShockwaveAnimation {
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
_ => (0.0, 0.0, 0.0),
};
if matches!(
stage_section,
Some(StageSection::Action | StageSection::Recover)

View File

@ -49,6 +49,7 @@ impl Animation for SpinAnimation {
next.main.position = Vec3::new(0.0, 0.0, 0.0);
next.main.orientation = Quaternion::rotation_x(0.0);
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
if matches!(
stage_section,
Some(StageSection::Action | StageSection::Recover)

View File

@ -13,8 +13,7 @@ pub struct Vertex {
impl Vertex {
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
const ATTRIBUTES: [wgpu::VertexAttribute; 2] =
wgpu::vertex_attr_array![0 => Float32x3, 1 => Uint32];
const ATTRIBUTES: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![0 => Float32x3];
wgpu::VertexBufferLayout {
array_stride: Self::STRIDE,
step_mode: wgpu::InputStepMode::Vertex,
@ -94,22 +93,7 @@ impl TrailPipeline {
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::GreaterEqual,
stencil: wgpu::StencilState {
front: wgpu::StencilFaceState::IGNORE,
back: wgpu::StencilFaceState::IGNORE,
read_mask: !0,
write_mask: !0,
},
bias: wgpu::DepthBiasState {
constant: 0,
slope_scale: 0.0,
clamp: 0.0,
},
}),
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: samples,
mask: !0,

View File

@ -9,7 +9,8 @@ mod shadow_map;
use locals::Locals;
use pipeline_creation::{
IngameAndShadowPipelines, InterfacePipelines, PipelineCreation, Pipelines, ShadowPipelines,
IngameAndShadowPipelines, InterfacePipelines, PipelineCreation, Pipelines, SecondPassPipelines,
ShadowPipelines,
};
use shaders::Shaders;
use shadow_map::{ShadowMap, ShadowMapRenderer};

View File

@ -4,8 +4,8 @@ use super::{
instances::Instances,
model::{DynamicModel, Model, SubModel},
pipelines::{
blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox,
sprite, terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup,
blit, bloom, debug, figure, fluid, lod_terrain, particle, shadow, skybox, sprite,
terrain, trail, ui, ColLights, GlobalsBindGroup, ShadowTexturesBindGroup,
},
},
Renderer, ShadowMap, ShadowMapRenderer,
@ -214,7 +214,10 @@ impl<'frame> Drawer<'frame> {
/// Returns None if the clouds pipeline is not available
pub fn second_pass(&mut self) -> Option<SecondPassDrawer> {
let pipeline = &self.borrow.pipelines.all()?.clouds;
let pipelines = super::SecondPassPipelines {
clouds: &self.borrow.pipelines.all()?.clouds,
trail: &self.borrow.pipelines.all()?.trail,
};
let encoder = self.encoder.as_mut().unwrap();
let device = self.borrow.device;
@ -237,7 +240,7 @@ impl<'frame> Drawer<'frame> {
Some(SecondPassDrawer {
render_pass,
borrow: &self.borrow,
pipeline,
pipelines,
})
}
@ -738,15 +741,6 @@ impl<'pass> FirstPassDrawer<'pass> {
ParticleDrawer { render_pass }
}
pub fn draw_trails(&mut self) -> 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 }
}
pub fn draw_sprites<'data: 'pass>(
&mut self,
globals: &'data sprite::SpriteGlobalsBindGroup,
@ -877,16 +871,10 @@ pub struct TrailDrawer<'pass_ref, 'pass: 'pass_ref> {
}
impl<'pass_ref, 'pass: 'pass_ref> TrailDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'data DynamicModel<trail::Vertex>,
model_len: u32,
) {
pub fn draw(&mut self, submodel: SubModel<'pass, trail::Vertex>) {
self.render_pass.set_vertex_buffer(0, submodel.buf());
self.render_pass
.set_vertex_buffer(0, model.submodel(0..model_len).buf());
self.render_pass
// TODO: since we cast to u32 maybe this should returned by the len/count functions?
.draw_indexed(0..model_len / 4 * 6, 0, 0..1);
.draw_indexed(0..submodel.len() / 4 * 6, 0, 0..1);
}
}
@ -943,16 +931,26 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
pub struct SecondPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
pipeline: &'pass clouds::CloudsPipeline,
pipelines: super::SecondPassPipelines<'pass>,
}
impl<'pass> SecondPassDrawer<'pass> {
pub fn draw_clouds(&mut self) {
self.render_pass.set_pipeline(&self.pipeline.pipeline);
self.render_pass
.set_pipeline(&self.pipelines.clouds.pipeline);
self.render_pass
.set_bind_group(1, &self.borrow.locals.clouds_bind.bind_group, &[]);
self.render_pass.draw(0..3, 0..1);
}
pub fn draw_trails(&mut self) -> 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 }
}
}
/// Third pass: postprocess + ui

View File

@ -33,6 +33,11 @@ pub struct Pipelines {
pub blit: blit::BlitPipeline,
}
pub struct SecondPassPipelines<'a> {
pub clouds: &'a clouds::CloudsPipeline,
pub trail: &'a trail::TrailPipeline,
}
/// Pipelines that are needed to render 3D stuff in-game
/// Use to decouple interface pipeline creation when initializing the renderer
pub struct IngamePipelines {

View File

@ -855,6 +855,9 @@ impl FigureMgr {
let body = *body;
// Only use trail manager when trails are enabled
let trail_mgr = scene_data.weapon_trails_enabled.then(|| &mut *trail_mgr);
let common_params = FigureUpdateCommonParameters {
entity: Some(entity),
pos: pos.0,
@ -1762,7 +1765,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -1962,7 +1965,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -2279,7 +2282,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -2637,7 +2640,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -2741,7 +2744,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -2824,7 +2827,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -3351,7 +3354,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -3438,7 +3441,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -3617,7 +3620,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -3909,7 +3912,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -4232,7 +4235,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -4315,7 +4318,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -4937,7 +4940,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -5178,7 +5181,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -5306,7 +5309,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -5369,7 +5372,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -5404,7 +5407,7 @@ impl FigureMgr {
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -5498,7 +5501,7 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update(
renderer,
Some(trail_mgr),
trail_mgr,
&mut update_buf,
&common_params,
state_animation_rate,
@ -6458,10 +6461,10 @@ impl<S: Skeleton> FigureState<S> {
((mat * trail_start).xyz(), (mat * trail_end).xyz())
});
let new_abs_trail_points = weapon_offsets.map(|(a, b)| (a + pos, b + pos));
let trail_mgr_offset = trail_mgr.offset;
let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, is_main_weapon);
if let (Some((p1, p2)), Some((p4, p3))) = (&old_abs_trail_points, new_abs_trail_points)
{
let trail_mgr_offset = trail_mgr.offset();
let quad_mesh = trail_mgr.entity_mesh_or_insert(entity, is_main_weapon);
let vertex = |p: anim::vek::Vec3<f32>| trail::Vertex {
pos: p.into_array(),
};

View File

@ -1153,10 +1153,6 @@ impl Scene {
self.particle_mgr
.render(&mut first_pass.draw_particles(), scene_data);
// Render weapon trails.
self.trail_mgr
.render(&mut first_pass.draw_trails(), scene_data);
// Render debug shapes
self.debug.render(&mut first_pass.draw_debug());
}

View File

@ -13,14 +13,14 @@ struct MeshKey {
}
pub struct TrailMgr {
/// Meshes for each entity
entity_meshes: HashMap<MeshKey, Mesh<TrailVertex>>,
/// Meshes for each entity, usize is the last offset tick it was updated
entity_meshes: HashMap<MeshKey, (Mesh<TrailVertex>, usize)>,
/// Position cache for things like projectiles
pos_cache: HashMap<EcsEntity, Pos>,
/// Offset
pub offset: usize,
offset: usize,
/// Dynamic model to upload to GPU
dynamic_model: DynamicModel<TrailVertex>,
@ -47,35 +47,6 @@ impl TrailMgr {
span!(_guard, "maintain", "TrailMgr::maintain");
if scene_data.weapon_trails_enabled {
// Update offset
self.offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
self.entity_meshes.values_mut().for_each(|mesh| {
// Shrink size of each quad over time
let vertices = mesh.vertices_mut_vec();
let last_offset =
(self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE;
let next_offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
for i in 0..TRAIL_DYNAMIC_MODEL_SIZE {
// Verts per quad are in b, c, a, d order
vertices[i * 4 + 2] = if i == next_offset {
vertices[i * 4]
} else {
vertices[i * 4 + 2] * TRAIL_SHRINKAGE
+ vertices[i * 4] * (1.0 - TRAIL_SHRINKAGE)
};
if i != last_offset {
// Avoid shrinking edge of most recent quad so that edges of quads align
vertices[i * 4 + 3] = vertices[i * 4 + 3] * TRAIL_SHRINKAGE
+ vertices[i * 4 + 1] * (1.0 - TRAIL_SHRINKAGE);
}
}
// Reset quad for each entity mesh at new offset
let zero = TrailVertex::zero();
mesh.replace_quad(self.offset * 4, Quad::new(zero, zero, zero, zero));
});
// Hack to shove trails in for projectiles
let ecs = scene_data.state.ecs();
for (entity, body, vel, pos) in (
@ -86,7 +57,8 @@ impl TrailMgr {
)
.join()
{
if !vel.0.is_approx_zero()
const MIN_SPEED: f32 = 15.0;
if vel.0.magnitude_squared() > MIN_SPEED.powi(2)
&& matches!(
body,
Body::Object(
@ -114,17 +86,50 @@ impl TrailMgr {
}
}
// Update offset
self.offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
self.entity_meshes.values_mut().for_each(|(mesh, _)| {
// TODO: Figure out how to do this in shader files instead
// Shrink size of each quad over time
let vertices = mesh.vertices_mut_vec();
let last_offset =
(self.offset + TRAIL_DYNAMIC_MODEL_SIZE - 1) % TRAIL_DYNAMIC_MODEL_SIZE;
let next_offset = (self.offset + 1) % TRAIL_DYNAMIC_MODEL_SIZE;
for i in 0..TRAIL_DYNAMIC_MODEL_SIZE {
// Verts per quad are in b, c, a, d order
let [b, c, a, d] = [0, 1, 2, 3].map(|offset| i * 4 + offset);
vertices[a] = if i == next_offset {
vertices[b]
} else {
vertices[a] * TRAIL_SHRINKAGE + vertices[b] * (1.0 - TRAIL_SHRINKAGE)
};
if i != last_offset {
// Avoid shrinking edge of most recent quad so that edges of quads align
vertices[d] =
vertices[d] * TRAIL_SHRINKAGE + vertices[c] * (1.0 - TRAIL_SHRINKAGE);
}
}
// Reset quad for each entity mesh at new offset
let zero = TrailVertex::zero();
mesh.replace_quad(self.offset * 4, Quad::new(zero, zero, zero, zero));
});
// 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, _)| mesh.iter().any(|vert| *vert != TrailVertex::zero()));
// .retain(|_, (_mesh, last_updated)| *last_updated == self.offset);
// Create dynamic model from currently existing meshes
// 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
let mut big_mesh = Mesh::new();
self.entity_meshes
.values()
// If any of the vertices in a mesh are non-zero, upload the entire mesh for the entity
.filter(|mesh| mesh.iter().any(|vert| *vert != TrailVertex::zero()))
.for_each(|mesh| big_mesh.push_mesh(mesh));
.filter(|(mesh, _)| mesh.iter().any(|vert| *vert != TrailVertex::zero()))
.for_each(|(mesh, _)| big_mesh.push_mesh(mesh));
// To avoid empty mesh
if big_mesh.is_empty() {
@ -132,21 +137,26 @@ impl TrailMgr {
big_mesh.push_quad(Quad::new(zero, zero, zero, zero));
}
// If dynamic model too small, resize
// 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());
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);
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);
}
}
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, self.model_len);
drawer.draw(self.dynamic_model.submodel(0..self.model_len))
}
}
@ -159,9 +169,11 @@ impl TrailMgr {
entity,
is_main_weapon,
};
self.entity_meshes
&mut self
.entity_meshes
.entry(key)
.or_insert_with(Self::default_trail_mesh)
.or_insert((Self::default_trail_mesh(), self.offset))
.0
}
fn default_trail_mesh() -> Mesh<TrailVertex> {
@ -172,4 +184,6 @@ impl TrailMgr {
}
mesh
}
pub fn offset(&self) -> usize { self.offset }
}

View File

@ -1561,12 +1561,17 @@ impl PlayState for SessionState {
);
}
// Clouds
{
prof_span!("clouds");
if let Some(mut second_pass) = drawer.second_pass() {
if let Some(mut second_pass) = drawer.second_pass() {
// Clouds
{
prof_span!("clouds");
second_pass.draw_clouds();
}
// Trails
{
prof_span!("trails");
second_pass.draw_trails();
}
}
// Bloom (call does nothing if bloom is off)
{