diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index da3ec4447a..6630c49dad 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -35,9 +35,9 @@ layout(location = 1) flat in vec3 f_norm; // const vec4 sun_pos = vec4(0.0); // #endif -layout(set = 1, binding = 2) +layout(set = 2, binding = 0) uniform texture2D t_col_light; -layout(set = 1, binding = 3) +layout(set = 2, binding = 1) uniform sampler s_col_light; //struct ShadowLocals { diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 6e04d71862..d6fac9973e 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -236,13 +236,9 @@ impl PlayState for CharSelectionState { let (humanoid_body, loadout) = Self::get_humanoid_body_inventory(&self.char_selection_ui, &client); - // Render the scene. - //self.scene - // .render(renderer, client.get_tick(), humanoid_body, loadout); + self.scene + .render(&mut drawer.first_pass(), client.get_tick(), humanoid_body, loadout); - // Render world - /* let mut first_pass = */ - drawer.first_pass(); // Clouds drawer.second_pass().draw_clouds(); // PostProcess and UI diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index 9d379c12d5..8540c8c361 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -13,7 +13,8 @@ pub struct SubModel<'a, V: Vertex> { } impl<'a, V: Vertex> SubModel<'a, V> { - pub(super) fn buf(&self) -> &wgpu::Buffer { self.buf } + pub(super) fn buf(&self) -> wgpu::BufferSlice<'a> { self.buf.slice(map_range(&self.vertex_range)) } + pub fn len(&self) -> u32 { self.vertex_range.end - self.vertex_range.start } } /// Represents a mesh that has been sent to the GPU. @@ -79,3 +80,5 @@ impl DynamicModel { pub fn len(&self) -> usize { self.vbuf.len() } } + +fn map_range(range: &Range) -> Range { (range.start as u64)..(range.end as u64) } diff --git a/voxygen/src/render/pipelines/clouds.rs b/voxygen/src/render/pipelines/clouds.rs index 4fb3e622b8..42f08f29c7 100644 --- a/voxygen/src/render/pipelines/clouds.rs +++ b/voxygen/src/render/pipelines/clouds.rs @@ -144,6 +144,7 @@ impl CloudsPipeline { vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, global_layout: &GlobalsLayouts, + sc_desc: &wgpu::SwapChainDescriptor, layout: &CloudsLayout, aa_mode: AaMode, ) -> Self { @@ -177,7 +178,7 @@ impl CloudsPipeline { rasterization_state: None, primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[wgpu::ColorStateDescriptor { - format: wgpu::TextureFormat::Rgba8UnormSrgb, + format: sc_desc.format, color_blend: wgpu::BlendDescriptor::REPLACE, alpha_blend: wgpu::BlendDescriptor::REPLACE, write_mask: wgpu::ColorWrite::ALL, diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index 9319e8162f..2063f6d4b3 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -1,5 +1,5 @@ use super::{ - super::{AaMode, GlobalsLayouts, Mesh, Model}, + super::{AaMode, Bound, Consts, GlobalsLayouts, Mesh, Model, Texture}, terrain::Vertex, }; use crate::mesh::greedy::GreedyMesh; @@ -24,6 +24,9 @@ pub struct BoneData { normals_mat: [[f32; 4]; 4], } +pub type BoundLocals = Bound<(Consts, Consts)>; +pub type ColLights = Bound; + impl Locals { pub fn new( model_mat: anim::vek::Mat4, @@ -97,6 +100,7 @@ pub type BoneMeshes = (Mesh, anim::vek::Aabb); pub struct FigureLayout { pub locals: wgpu::BindGroupLayout, + pub col_light: wgpu::BindGroupLayout, } impl FigureLayout { @@ -127,9 +131,14 @@ impl FigureLayout { }, count: None, }, + ], + }), + col_light: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ // col lights wgpu::BindGroupLayoutEntry { - binding: 2, + binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Texture { sample_type: wgpu::TextureSampleType::Float { filterable: true }, @@ -139,15 +148,67 @@ impl FigureLayout { count: None, }, wgpu::BindGroupLayoutEntry { - binding: 3, + binding: 1, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { filtering: true, comparison: false }, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: false, + }, count: None, }, ], }), } } + + pub fn bind_locals( + &self, + device: &wgpu::Device, + locals: Consts, + bone_data: Consts, + ) -> BoundLocals { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.locals, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: locals.buf().as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: bone_data.buf().as_entire_binding(), + }, + ], + }); + + BoundLocals { + bind_group, + with: (locals, bone_data), + } + } + + pub fn bind_texture(&self, device: &wgpu::Device, col_light: Texture) -> ColLights { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.col_light, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&col_light.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&col_light.sampler), + }, + ], + }); + + ColLights { + bind_group, + with: col_light, + } + } } pub struct FigurePipeline { @@ -169,7 +230,7 @@ impl FigurePipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Figure pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&global_layout.globals, &layout.locals], + bind_group_layouts: &[&global_layout.globals, &layout.locals, &layout.col_light], }); let samples = match aa_mode { diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index b16b242bbc..5293118487 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -1,4 +1,4 @@ -use super::super::{AaMode, GlobalsLayouts}; +use super::super::{AaMode, Bound, Consts, GlobalsLayouts}; use bytemuck::{Pod, Zeroable}; use vek::*; @@ -132,6 +132,8 @@ impl Locals { } } +pub type BoundLocals = Bound>; + pub struct TerrainLayout { pub locals: wgpu::BindGroupLayout, } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 96b0bde915..b5b1b55bb4 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -613,13 +613,13 @@ impl Renderer { mip_level_count: levels, sample_count, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, + format: wgpu::TextureFormat::Bgra8UnormSrgb, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT, }); tex.create_view(&wgpu::TextureViewDescriptor { label: None, - format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + format: Some(wgpu::TextureFormat::Bgra8UnormSrgb), dimension: Some(wgpu::TextureViewDimension::D2), // TODO: why is this not Color? aspect: wgpu::TextureAspect::All, @@ -2161,6 +2161,7 @@ fn create_pipelines( &create_shader("clouds-frag", ShaderKind::Fragment)?, // TODO: pass in format of intermediate color buffer &layouts.global, + sc_desc, &layouts.clouds, mode.aa, ); diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 691d9660a7..58e3526d5d 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -1,7 +1,7 @@ use super::{ super::{ consts::Consts, - pipelines::{lod_terrain, ui, GlobalModel, GlobalsBindGroup}, + pipelines::{figure, lod_terrain, ui, GlobalModel, GlobalsBindGroup}, texture::Texture, }, Renderer, @@ -36,4 +36,20 @@ impl Renderer { pub fn ui_bind_texture(&self, texture: &Texture) -> ui::TextureBindGroup { self.layouts.ui.bind_texture(&self.device, texture) } + + pub fn create_figure_bound_locals( + &mut self, + locals: &[figure::Locals], + bone_data: &[figure::BoneData], + ) -> figure::BoundLocals { + let locals = self.create_consts(locals); + let bone_data = self.create_consts(bone_data); + self.layouts + .figure + .bind_locals(&self.device, locals, bone_data) + } + + pub fn figure_bind_texture(&self, col_light: Texture) -> figure::ColLights { + self.layouts.figure.bind_texture(&self.device, col_light) + } } diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 4812aaa4dd..2a4f81395b 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -3,7 +3,7 @@ use super::{ buffer::Buffer, consts::Consts, instances::Instances, - model::{DynamicModel, Model}, + model::{DynamicModel, SubModel,Model}, pipelines::{ clouds, figure, fluid, particle, postprocess, sprite, terrain, ui, GlobalsBindGroup, Light, Shadow, @@ -109,7 +109,6 @@ impl<'a> Drawer<'a> { store: true, }, }], - // TODO: do we need this? depth_stencil_attachment: None, }); @@ -149,49 +148,37 @@ impl<'a> FirstPassDrawer<'a> { self.render_pass.set_bind_group(0, &globals.bind_group, &[]); self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); self.render_pass.draw(verts, 0..1); - } + }*/ pub fn draw_figure<'b: 'a>( &mut self, - model: &'b Model, - locals: &'b Consts, - bones: &'b Consts, - globals: &'b Consts, - lights: &'b Consts, - shadows: &'b Consts, - verts: Range, + model: SubModel<'b, terrain::Vertex>, + locals: &'b figure::BoundLocals, + col_lights: &'b figure::ColLights ) { self.render_pass .set_pipeline(&self.renderer.figure_pipeline.pipeline); - self.render_pass.set_bind_group(0, &globals.bind_group, &[]); - self.render_pass.set_bind_group(1, &lights.bind_group, &[]); - self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); - self.render_pass.set_bind_group(3, &locals.bind_group, &[]); - self.render_pass.set_bind_group(4, &bones.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); - self.render_pass.draw(verts, 0..1); + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_bind_group(2, &col_lights.bind_group, &[]); + self.render_pass + .set_vertex_buffer(0, model.buf()); + self.render_pass.draw(0..model.len(), 0..1); } pub fn draw_terrain<'b: 'a>( &mut self, - model: &'b Model, - locals: &'b Consts, - globals: &'b Consts, - lights: &'b Consts, - shadows: &'b Consts, - verts: Range, + model: &'b SubModel, + locals: &'b terrain::BoundLocals, ) { self.render_pass .set_pipeline(&self.renderer.terrain_pipeline.pipeline); - self.render_pass.set_bind_group(0, &globals.bind_group, &[]); - self.render_pass.set_bind_group(1, &lights.bind_group, &[]); - self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); - self.render_pass.set_bind_group(3, &locals.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); - self.render_pass.draw(verts, 0..1) + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass + .set_vertex_buffer(0, model.buf()); + self.render_pass.draw(0..model.len(), 0..1) } - pub fn draw_fluid<'b: 'a>( + /*pub fn draw_fluid<'b: 'a>( &mut self, model: &'b Model, locals: &'b Consts, diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 971488e85b..5ad5afe386 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -61,8 +61,7 @@ pub type CameraData<'a> = (&'a Camera, f32); /// Enough data to render a figure model. pub type FigureModelRef<'a> = ( - &'a Consts, - &'a Consts, + &'a pipelines::figure::BoundLocals, SubModel<'a, TerrainVertex>, &'a Texture, /* */ ); @@ -80,7 +79,7 @@ pub struct FigureModelEntry { /// Texture used to store color/light information for this figure entry. /* TODO: Consider using mipmaps instead of storing multiple texture atlases for different * LOD levels. */ - col_lights: Texture, /* */ + col_lights: pipelines::figure::ColLights, /// Vertex ranges stored in this figure entry; there may be several for one /// figure, because of LOD models. lod_vertex_ranges: [Range; N], @@ -3562,7 +3561,7 @@ impl FigureMgr { // Don't render dead entities .filter(|(_, _, _, _, health, _, _)| health.map_or(true, |h| !h.is_dead)) .for_each(|(entity, pos, _, body, _, inventory, _)| { - if let Some((locals, bone_consts, model, _)) = self.get_model_for_render( + if let Some((bound, model, _)) = self.get_model_for_render( tick, camera, None, @@ -3620,7 +3619,7 @@ impl FigureMgr { let is_player = entity == player_entity; if !is_player { - if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( + if let Some((bound, model, col_lights)) = self.get_model_for_render( tick, camera, character_state, @@ -3669,7 +3668,7 @@ impl FigureMgr { let inventory_storage = ecs.read_storage::(); let inventory = inventory_storage.get(player_entity); - if let Some((locals, bone_consts, model, col_lights)) = self.get_model_for_render( + if let Some((bound, model, col_lights)) = self.get_model_for_render( tick, camera, character_state, @@ -3751,14 +3750,13 @@ impl FigureMgr { }, } = self; let col_lights = &*col_lights_; - if let Some((locals, bone_consts, model_entry)) = match body { + if let Some((bound, model_entry)) = match body { Body::Humanoid(body) => character_states .get(&entity) .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), model_cache.get_model( col_lights, *body, @@ -3774,8 +3772,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), quadruped_small_model_cache.get_model( col_lights, *body, @@ -3791,8 +3788,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), quadruped_medium_model_cache.get_model( col_lights, *body, @@ -3808,8 +3804,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), quadruped_low_model_cache.get_model( col_lights, *body, @@ -3825,8 +3820,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), bird_medium_model_cache.get_model( col_lights, *body, @@ -3842,8 +3836,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), fish_medium_model_cache.get_model( col_lights, *body, @@ -3859,8 +3852,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), theropod_model_cache.get_model( col_lights, *body, @@ -3876,8 +3868,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), dragon_model_cache.get_model( col_lights, *body, @@ -3893,8 +3884,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), bird_small_model_cache.get_model( col_lights, *body, @@ -3910,8 +3900,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), fish_small_model_cache.get_model( col_lights, *body, @@ -3927,8 +3916,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), biped_large_model_cache.get_model( col_lights, *body, @@ -3944,8 +3932,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), golem_model_cache.get_model( col_lights, *body, @@ -3961,8 +3948,7 @@ impl FigureMgr { .filter(|state| filter_state(&*state)) .map(move |state| { ( - state.locals(), - state.bone_consts(), + state.bound(), object_model_cache.get_model( col_lights, *body, @@ -3987,7 +3973,7 @@ impl FigureMgr { model_entry.lod_model(0) }; - Some((locals, bone_consts, model, col_lights_.texture(model_entry))) + Some((bound, model, col_lights_.texture(model_entry))) } else { // trace!("Body has no saved figure"); None @@ -4013,8 +3999,10 @@ impl FigureColLights { } /// Find the correct texture for this model entry. - pub fn texture<'a, const N: usize>(&'a self, model: &'a FigureModelEntry) -> &'a Texture /* */ - { + pub fn texture<'a, const N: usize>( + &'a self, + model: &'a FigureModelEntry, + ) -> &'a pipelines::figure::ColLights { /* &self.col_lights */ &model.col_lights } @@ -4038,6 +4026,7 @@ impl FigureColLights { .allocate(guillotiere::Size::new(tex_size.x as i32, tex_size.y as i32)) .expect("Not yet implemented: allocate new atlas on allocation failure."); let col_lights = pipelines::shadow::create_col_lights(renderer, (tex, tex_size)); + let col_lights = renderer.figure_bind_texture(col_lights); let model_len = u32::try_from(opaque.vertices().len()) .expect("The model size for this figure does not fit in a u32!"); let model = renderer.create_model(&opaque)?; @@ -4097,8 +4086,6 @@ impl FigureColLights { } pub struct FigureStateMeta { - bone_consts: Consts, - locals: Consts, lantern_offset: anim::vek::Vec3, state_time: f64, last_ori: anim::vek::Quaternion, @@ -4110,6 +4097,7 @@ pub struct FigureStateMeta { last_light: f32, last_glow: f32, acc_vel: f32, + bound: pipelines::figure::BoundLocals, } impl FigureStateMeta { @@ -4144,8 +4132,6 @@ impl FigureState { let bone_consts = figure_bone_data_from_anim(&buf); Self { meta: FigureStateMeta { - bone_consts: renderer.create_consts(bone_consts), - locals: renderer.create_consts(&[FigureLocals::default()]), lantern_offset, state_time: 0.0, last_ori: Ori::default().into(), @@ -4157,6 +4143,7 @@ impl FigureState { last_light: 1.0, last_glow: 0.0, acc_vel: 0.0, + bound: renderer.create_figure_bound_locals(&[FigureLocals::default()], bone_consts), }, skeleton, } @@ -4267,16 +4254,13 @@ impl FigureState { self.last_light, self.last_glow, ); - renderer.update_consts(&mut self.locals, &[locals]); + renderer.update_consts(&mut self.meta.bound.0, &[locals]); let lantern_offset = anim::compute_matrices(&self.skeleton, mat, buf); let new_bone_consts = figure_bone_data_from_anim(buf); - renderer.update_consts( - &mut self.meta.bone_consts, - &new_bone_consts[0..S::BONE_COUNT], - ); + renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]); self.lantern_offset = lantern_offset; let smoothing = (5.0 * dt).min(1.0); @@ -4293,9 +4277,7 @@ impl FigureState { } } - pub fn locals(&self) -> &Consts { &self.locals } - - pub fn bone_consts(&self) -> &Consts { &self.bone_consts } + pub fn bound(&self) -> &pipelines::figure::BoundLocals { &self.bound } pub fn skeleton_mut(&mut self) -> &mut S { &mut self.skeleton } } diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 86b0224b86..3ad1caa773 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -1,7 +1,7 @@ use crate::{ mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain}, render::{ - create_skybox_mesh, BoneMeshes, Consts, FigureModel, GlobalModel, Globals, + create_skybox_mesh, BoneMeshes, Consts, FigureModel, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Mesh, Model, Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex, }, @@ -339,20 +339,13 @@ impl Scene { pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group } - pub fn render( - &mut self, - renderer: &mut Renderer, + pub fn render<'a>( + &'a self, + drawer: &mut FirstPassDrawer<'a>, tick: u64, body: Option, inventory: Option<&Inventory>, ) { - /*renderer.render_skybox( - &self.skybox.model, - &self.data, - &self.skybox.locals, - &self.lod, - );*/ - if let Some(body) = body { let model = &self.figure_model_cache.get_model( &self.col_lights, @@ -364,40 +357,20 @@ impl Scene { ); if let Some(model) = model { - // renderer.render_figure( - // &model.models[0], - // &self.col_lights.texture(model), - // &self.data, - // self.figure_state.locals(), - // self.figure_state.bone_consts(), - // &self.lod, - // ); + drawer.draw_figure( + model.lod_model(0), + self.figure_state.bound(), + &self.col_lights.texture(model), + ); } } if let Some((model, state)) = &self.backdrop { - /*renderer.render_figure( - &model.models[0], + drawer.draw_figure( + model.lod_model(0), + state.bound(), &self.col_lights.texture(model), - &self.data, - state.locals(), - state.bone_consts(), - &self.lod, - );*/ + ); } - - // renderer.render_clouds( - // &self.clouds.model, - // &self.data.globals, - // &self.clouds.locals, - // &self.lod, - // ); - - // renderer.render_post_process( - // &self.postprocess.model, - // &self.data.globals, - // &self.postprocess.locals, - // &self.lod, - // ); } }