Avoid extra set_pipeline calls

This commit is contained in:
Imbris 2020-12-21 20:53:37 -05:00
parent b2f94c1485
commit 624183e3f3
7 changed files with 325 additions and 316 deletions

View File

@ -42,8 +42,9 @@ pub use self::{
},
renderer::{
drawer::{
Drawer, FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer,
ShadowDrawer, ThirdPassDrawer, UiDrawer,
ChunkSpriteDrawer, Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer,
ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer,
TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, UiDrawer,
},
ColLightInfo, Renderer,
},

View File

@ -36,6 +36,38 @@ impl<'a> Drawer<'a> {
}
}
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
let mut render_pass =
self.encoder
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[],
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &shadow_renderer.directed_depth.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: true,
}),
stencil_ops: None,
},
),
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
Some(ShadowPassDrawer {
render_pass,
renderer: &self.renderer,
shadow_renderer,
})
} else {
None
}
}
pub fn first_pass(&mut self) -> FirstPassDrawer {
let mut render_pass =
self.encoder
@ -71,38 +103,6 @@ impl<'a> Drawer<'a> {
}
}
pub fn shadow_pass(&mut self) -> Option<ShadowDrawer> {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
let mut render_pass =
self.encoder
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[],
depth_stencil_attachment: Some(
wgpu::RenderPassDepthStencilAttachmentDescriptor {
attachment: &shadow_renderer.directed_depth.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: true,
}),
stencil_ops: None,
},
),
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
Some(ShadowDrawer {
render_pass,
renderer: &self.renderer,
shadow_renderer,
})
} else {
None
}
}
pub fn second_pass(&mut self) -> SecondPassDrawer {
let mut render_pass =
self.encoder
@ -154,10 +154,11 @@ impl<'a> Drawer<'a> {
}
}
pub fn draw_point_shadow<'b: 'a>(
pub fn draw_point_shadows<'data: 'a>(
&mut self,
matrices: &[shadow::PointLightMatrix; 126],
chunks: impl Clone + Iterator<Item = (&'b Model<terrain::Vertex>, &'b terrain::BoundLocals)>,
chunks: impl Clone
+ Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
) {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
@ -228,57 +229,110 @@ impl<'a> Drop for Drawer<'a> {
}
}
pub struct FirstPassDrawer<'a> {
pub(super) render_pass: wgpu::RenderPass<'a>,
pub renderer: &'a Renderer,
// Shadow pass
pub struct ShadowPassDrawer<'pass> {
render_pass: wgpu::RenderPass<'pass>,
pub renderer: &'pass Renderer,
shadow_renderer: &'pass ShadowMapRenderer,
}
impl<'a> FirstPassDrawer<'a> {
pub fn draw_skybox<'b: 'a>(&mut self, model: &'b Model<skybox::Vertex>) {
impl<'pass> ShadowPassDrawer<'pass> {
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
FigureShadowDrawer {
render_pass: &mut self.render_pass,
}
}
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
TerrainShadowDrawer {
render_pass: &mut self.render_pass,
}
}
}
pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: SubModel<'data, terrain::Vertex>,
locals: &'data figure::BoundLocals,
) {
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 struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'data Model<terrain::Vertex>,
locals: &'data terrain::BoundLocals,
) {
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
}
}
// First pass
pub struct FirstPassDrawer<'pass> {
pub(super) render_pass: wgpu::RenderPass<'pass>,
pub renderer: &'pass Renderer,
}
impl<'pass> FirstPassDrawer<'pass> {
pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
self.render_pass
.set_pipeline(&self.renderer.skybox_pipeline.pipeline);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
}
pub fn draw_lod_terrain<'b: 'a>(&mut self, model: &'b Model<lod_terrain::Vertex>) {
pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
self.render_pass
.set_pipeline(&self.renderer.lod_terrain_pipeline.pipeline);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
}
pub fn draw_figure<'b: 'a>(
&mut self,
model: SubModel<'b, terrain::Vertex>,
locals: &'b figure::BoundLocals,
col_lights: &'b ColLights<figure::Locals>,
) {
pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.figure_pipeline.pipeline);
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
self.render_pass
.set_bind_group(3, &col_lights.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf());
self.render_pass.draw(0..model.len(), 0..1);
FigureDrawer {
render_pass: &mut self.render_pass,
}
}
pub fn draw_terrain<'b: 'a>(
pub fn draw_terrain<'data: 'pass>(
&mut self,
model: &'b Model<terrain::Vertex>,
locals: &'b terrain::BoundLocals,
col_lights: &'b ColLights<terrain::Locals>,
) {
col_lights: &'data ColLights<terrain::Locals>,
) -> TerrainDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.terrain_pipeline.pipeline);
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
self.render_pass
.set_bind_group(3, &col_lights.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1)
TerrainDrawer {
render_pass: &mut self.render_pass,
}
}
pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'a> {
pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.particle_pipeline.pipeline);
@ -287,29 +341,24 @@ impl<'a> FirstPassDrawer<'a> {
}
}
pub fn draw_sprite<'b: 'a>(
pub fn draw_sprites<'data: 'pass>(
&mut self,
model: &'b Model<sprite::Vertex>,
instances: &'b Instances<sprite::Instance>,
terrain_locals: &'b terrain::BoundLocals,
locals: &'b sprite::BoundLocals,
col_lights: &'b ColLights<sprite::Locals>,
) {
col_lights: &'data ColLights<sprite::Locals>,
) -> SpriteDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.sprite_pipeline.pipeline);
self.render_pass
.set_bind_group(2, &terrain_locals.bind_group, &[]);
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass
.set_bind_group(4, &col_lights.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass
.set_vertex_buffer(1, instances.buf().slice(..));
self.render_pass
.draw(0..model.len() as u32, 0..instances.count() as u32);
SpriteDrawer {
render_pass: &mut self.render_pass,
}
}
pub fn draw_fluid<'b: 'a>(&mut self, waves: &'b fluid::BindGroup) -> FluidDrawer<'_, 'a> {
pub fn draw_fluid<'data: 'pass>(
&mut self,
waves: &'data fluid::BindGroup,
) -> FluidDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.fluid_pipeline.pipeline);
self.render_pass.set_bind_group(2, &waves.bind_group, &[]);
@ -320,6 +369,42 @@ impl<'a> FirstPassDrawer<'a> {
}
}
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: SubModel<'data, terrain::Vertex>,
locals: &'data figure::BoundLocals,
// TODO: don't rebind this every time once they are shared between figures
col_lights: &'data ColLights<figure::Locals>,
) {
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
self.render_pass
.set_bind_group(3, &col_lights.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf());
self.render_pass.draw(0..model.len(), 0..1);
}
}
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'data Model<terrain::Vertex>,
locals: &'data terrain::BoundLocals,
) {
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1)
}
}
pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
@ -341,35 +426,40 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
}
}
pub struct ShadowDrawer<'pass> {
render_pass: wgpu::RenderPass<'pass>,
pub renderer: &'pass Renderer,
shadow_renderer: &'pass ShadowMapRenderer,
pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass> ShadowDrawer<'pass> {
pub fn draw_figure_shadow<'b: 'pass>(
impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
pub fn in_chunk<'data: 'pass>(
&mut self,
model: SubModel<'b, terrain::Vertex>,
locals: &'b figure::BoundLocals,
) {
terrain_locals: &'data terrain::BoundLocals,
) -> ChunkSpriteDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
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);
}
.set_bind_group(2, &terrain_locals.bind_group, &[]);
pub fn draw_terrain_shadow<'b: 'pass>(
ChunkSpriteDrawer {
render_pass: &mut self.render_pass,
}
}
}
pub struct ChunkSpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: &'pass_ref mut wgpu::RenderPass<'pass>,
}
impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'b Model<terrain::Vertex>,
locals: &'b terrain::BoundLocals,
model: &'data Model<sprite::Vertex>,
instances: &'data Instances<sprite::Instance>,
locals: &'data sprite::BoundLocals,
) {
self.render_pass
.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
self.render_pass
.set_vertex_buffer(1, instances.buf().slice(..));
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
self.render_pass
.draw(0..model.len() as u32, 0..instances.count() as u32);
}
}
@ -389,13 +479,14 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
}
}
pub struct SecondPassDrawer<'a> {
pub(super) render_pass: wgpu::RenderPass<'a>,
pub renderer: &'a Renderer,
// Second pass: clouds
pub struct SecondPassDrawer<'pass> {
pub(super) render_pass: wgpu::RenderPass<'pass>,
pub renderer: &'pass Renderer,
}
impl<'a> SecondPassDrawer<'a> {
pub fn draw_clouds<'b: 'a>(&mut self) {
impl<'pass> SecondPassDrawer<'pass> {
pub fn draw_clouds(&mut self) {
self.render_pass
.set_pipeline(&self.renderer.clouds_pipeline.pipeline);
self.render_pass
@ -404,13 +495,14 @@ impl<'a> SecondPassDrawer<'a> {
}
}
pub struct ThirdPassDrawer<'a> {
render_pass: wgpu::RenderPass<'a>,
renderer: &'a Renderer,
// Third pass: postprocess + ui
pub struct ThirdPassDrawer<'pass> {
render_pass: wgpu::RenderPass<'pass>,
renderer: &'pass Renderer,
}
impl<'a> ThirdPassDrawer<'a> {
pub fn draw_post_process<'b: 'a>(&mut self) {
impl<'pass> ThirdPassDrawer<'pass> {
pub fn draw_post_process(&mut self) {
self.render_pass
.set_pipeline(&self.renderer.postprocess_pipeline.pipeline);
self.render_pass
@ -418,7 +510,7 @@ impl<'a> ThirdPassDrawer<'a> {
self.render_pass.draw(0..3, 0..1);
}
pub fn draw_ui(&mut self) -> UiDrawer<'_, 'a> {
pub fn draw_ui(&mut self) -> UiDrawer<'_, 'pass> {
self.render_pass
.set_pipeline(&self.renderer.ui_pipeline.pipeline);
@ -443,7 +535,7 @@ impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> {
pub fn prepare<'data: 'pass>(
&mut self,
locals: &'data ui::BoundLocals,
//texture: &'b ui::TextureBindGroup,
//texture: &'data ui::TextureBindGroup,
buf: &'data DynamicModel<ui::Vertex>,
scissor: Aabr<u16>,
) -> PreparedUiDrawer<'_, 'pass> {
@ -467,8 +559,9 @@ impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> {
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
}
//pub fn set_texture<'b: 'a>(&mut self, texture: &'b ui::TextureBindGroup) {
// self.render_pass.set_bind_group(1, &texture.bind_group, &[]);
//pub fn set_texture<'data: 'pass>(&mut self, texture: &'data
// ui::TextureBindGroup) { self.render_pass.set_bind_group(1,
// &texture.bind_group, &[]);
//}
pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel<ui::Vertex>) {

View File

@ -8,8 +8,9 @@ use crate::{
ecs::comp::Interpolated,
render::{
pipelines::{self, ColLights},
ColLightInfo, FigureBoneData, FigureLocals, FigureModel, FirstPassDrawer, GlobalModel,
LodData, Mesh, RenderError, Renderer, ShadowDrawer, SubModel, TerrainVertex,
ColLightInfo, FigureBoneData, FigureDrawer, FigureLocals, FigureModel, FigureShadowDrawer,
FirstPassDrawer, GlobalModel, LodData, Mesh, RenderError, Renderer, SubModel,
TerrainVertex,
},
scene::{
camera::{Camera, CameraMode, Dependents},
@ -4397,7 +4398,7 @@ impl FigureMgr {
pub fn render_shadows<'a>(
&'a self,
drawer: &mut ShadowDrawer<'a>,
drawer: &mut FigureShadowDrawer<'_, 'a>,
state: &State,
tick: u64,
(camera, figure_lod_render_distance): CameraData,
@ -4430,7 +4431,7 @@ impl FigureMgr {
figure_lod_render_distance * scale.map_or(1.0, |s| s.0),
|state| state.can_shadow_sun(),
) {
drawer.draw_figure_shadow(model, bound);
drawer.draw(model, bound);
}
});
}
@ -4438,12 +4439,10 @@ impl FigureMgr {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn render<'a>(
&'a self,
drawer: &mut FirstPassDrawer<'a>,
drawer: &mut FigureDrawer<'_, 'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
global: &GlobalModel,
lod: &LodData,
(camera, figure_lod_render_distance): CameraData,
) {
span!(_guard, "render", "FigureManager::render");
@ -4452,36 +4451,33 @@ impl FigureMgr {
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(player_entity);
for (entity, pos, _, body, _, inventory, scale) in (
for (entity, pos, body, _, inventory, scale) in (
&ecs.entities(),
&ecs.read_storage::<Pos>(),
ecs.read_storage::<Ori>().maybe(),
&ecs.read_storage::<Body>(),
ecs.read_storage::<Health>().maybe(),
ecs.read_storage::<Inventory>().maybe(),
ecs.read_storage::<Scale>().maybe(),
ecs.read_storage::<Scale>().maybe()
)
.join()
// Don't render dead entities
.filter(|(_, _, _, _, health, _, _)| health.map_or(true, |h| !h.is_dead))
.filter(|(_, _, _, health, _)| health.map_or(true, |h| !h.is_dead))
// Don't render player
.filter(|(entity, _, _, _, _)| *entity != player_entity)
{
let is_player = entity == player_entity;
if !is_player {
if let Some((bound, model, col_lights)) = self.get_model_for_render(
tick,
camera,
character_state,
entity,
body,
inventory,
false,
pos.0,
figure_lod_render_distance * scale.map_or(1.0, |s| s.0),
|state| state.visible(),
) {
drawer.draw_figure(model, bound, col_lights);
}
if let Some((bound, model, col_lights)) = self.get_model_for_render(
tick,
camera,
character_state,
entity,
body,
inventory,
false,
pos.0,
figure_lod_render_distance * scale.map_or(1.0, |s| s.0),
|state| state.visible(),
) {
drawer.draw(model, bound, col_lights);
}
}
}
@ -4489,12 +4485,10 @@ impl FigureMgr {
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn render_player<'a>(
&'a self,
drawer: &mut FirstPassDrawer<'a>,
drawer: &mut FigureDrawer<'_, 'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
global: &GlobalModel,
lod: &LodData,
(camera, figure_lod_render_distance): CameraData,
) {
span!(_guard, "render_player", "FigureManager::render_player");
@ -4528,7 +4522,7 @@ impl FigureMgr {
figure_lod_render_distance,
|state| state.visible(),
) {
drawer.draw_figure(model, bound, col_lights);
drawer.draw(model, bound, col_lights);
/*renderer.render_player_shadow(
model,
&col_lights,

View File

@ -18,7 +18,7 @@ use crate::{
render::{
create_skybox_mesh, CloudsLocals, Consts, Drawer, FirstPassDrawer, GlobalModel, Globals,
GlobalsBindGroup, Light, Model, PointLightMatrix, PostProcessLocals, Renderer, Shadow,
ShadowDrawer, ShadowLocals, SkyboxVertex,
ShadowLocals, SkyboxVertex,
},
settings::Settings,
window::{AnalogGameInput, Event},
@ -1034,90 +1034,10 @@ impl Scene {
pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group }
pub fn render_terrain_shadows<'a>(
&'a self,
drawer: &mut ShadowDrawer<'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
scene_data: &SceneData,
) {
let sun_dir = scene_data.get_sun_dir();
let is_daylight = sun_dir.z < 0.0;
let focus_pos = self.camera.get_focus_pos();
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let global = &self.data;
let light_data = (is_daylight, &*self.light_data);
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
// would instead have this as an extension.
if drawer.renderer.render_mode().shadow.is_map()
&& (is_daylight || !light_data.1.is_empty())
{
// Render terrain shadows.
self.terrain
.render_shadows(drawer, global, light_data, focus_pos);
}
}
pub fn render_point_shadows<'a>(
&'a self,
drawer: &mut Drawer<'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
scene_data: &SceneData,
) {
let sun_dir = scene_data.get_sun_dir();
let is_daylight = sun_dir.z < 0.0;
let focus_pos = self.camera.get_focus_pos();
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let global = &self.data;
let light_data = (is_daylight, &*self.light_data);
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
if drawer.renderer.render_mode().shadow.is_map()
&& (is_daylight || !light_data.1.is_empty())
{
// Render terrain shadows.
self.terrain
.render_point_shadows(drawer, global, light_data, focus_pos);
}
}
pub fn render_figure_shadows<'a>(
&'a self,
drawer: &mut ShadowDrawer<'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
scene_data: &SceneData,
) {
let sun_dir = scene_data.get_sun_dir();
let is_daylight = sun_dir.z < 0.0;
let focus_pos = self.camera.get_focus_pos();
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let global = &self.data;
let light_data = (is_daylight, &*self.light_data);
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
// would instead have this as an extension.
if drawer.renderer.render_mode().shadow.is_map()
&& (is_daylight || !light_data.1.is_empty())
{
// Render figure shadows.
self.figure_mgr
.render_shadows(drawer, state, tick, camera_data);
}
}
/// Render the scene using the provided `FirstPassDrawer`.
/// Render the scene using the provided `Drawer`.
pub fn render<'a>(
&'a self,
drawer: &mut FirstPassDrawer<'a>,
drawer: &mut Drawer<'a>,
state: &State,
player_entity: EcsEntity,
tick: u64,
@ -1129,26 +1049,63 @@ impl Scene {
let focus_pos = self.camera.get_focus_pos();
let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc());
let global = &self.data;
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
let lod = self.lod.get_data();
// would instead have this as an extension.
if drawer.renderer.render_mode().shadow.is_map()
&& (is_daylight || !self.light_data.is_empty())
{
if is_daylight {
if let Some(mut shadow_pass) = drawer.shadow_pass() {
// Render terrain directed shadows.
self.terrain
.render_shadows(&mut shadow_pass.draw_terrain_shadows(), focus_pos);
self.figure_mgr
.render_player(drawer, state, player_entity, tick, global, lod, camera_data);
// Render figure directed shadows.
self.figure_mgr.render_shadows(
&mut shadow_pass.draw_figure_shadows(),
state,
tick,
camera_data,
);
}
}
self.terrain.render(drawer, focus_pos);
// Render terrain point light shadows.
drawer.draw_point_shadows(
&self.data.point_light_matrices,
self.terrain.chunks_for_point_shadows(focus_pos),
)
}
self.figure_mgr
.render(drawer, state, player_entity, tick, global, lod, camera_data);
let mut first_pass = drawer.first_pass();
self.lod.render(drawer);
self.figure_mgr.render_player(
&mut first_pass.draw_figures(),
state,
player_entity,
tick,
camera_data,
);
self.terrain.render(&mut first_pass, focus_pos);
self.figure_mgr.render(
&mut first_pass.draw_figures(),
state,
player_entity,
tick,
camera_data,
);
self.lod.render(&mut first_pass);
// Render the skybox.
drawer.draw_skybox(&self.skybox.model);
first_pass.draw_skybox(&self.skybox.model);
// Draws translucent terrain and sprites
self.terrain.render_translucent(
drawer,
&mut first_pass,
focus_pos,
cam_pos,
scene_data.sprite_render_distance,
@ -1156,6 +1113,6 @@ impl Scene {
// Render particle effects.
self.particle_mgr
.render(&mut drawer.draw_particles(), scene_data);
.render(&mut first_pass.draw_particles(), scene_data);
}
}

View File

@ -354,6 +354,7 @@ impl Scene {
body: Option<humanoid::Body>,
inventory: Option<&Inventory>,
) {
let mut figure_drawer = drawer.draw_figures();
if let Some(body) = body {
let model = &self.figure_model_cache.get_model(
&self.col_lights,
@ -365,7 +366,7 @@ impl Scene {
);
if let Some(model) = model {
drawer.draw_figure(
figure_drawer.draw(
model.lod_model(0),
self.figure_state.bound(),
&self.col_lights.texture(model),
@ -374,7 +375,7 @@ impl Scene {
}
if let Some((model, state)) = &self.backdrop {
drawer.draw_figure(
figure_drawer.draw(
model.lod_model(0),
state.bound(),
&self.col_lights.texture(model),

View File

@ -10,8 +10,8 @@ use crate::{
render::{
pipelines::{self, ColLights},
ColLightInfo, Consts, Drawer, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel,
Instances, LodData, Mesh, Model, RenderError, Renderer, ShadowDrawer, SpriteInstance,
SpriteLocals, SpriteVertex, TerrainLocals, TerrainVertex, Texture,
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals,
SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture,
},
};
@ -1264,9 +1264,7 @@ impl<V: RectRasterableVol> Terrain<V> {
pub fn render_shadows<'a>(
&'a self,
drawer: &mut ShadowDrawer<'a>,
global: &GlobalModel,
(is_daylight, light_data): super::LightData,
drawer: &mut TerrainShadowDrawer<'_, 'a>,
focus_pos: Vec3<f32>,
) {
span!(_guard, "render_shadows", "Terrain::render_shadows");
@ -1286,28 +1284,28 @@ impl<V: RectRasterableVol> Terrain<V> {
// NOTE: We also render shadows for dead chunks that were found to still be
// potential shadow casters, to avoid shadows suddenly disappearing at
// very steep sun angles (e.g. sunrise / sunset).
if is_daylight {
chunk_iter
.clone()
.filter(|chunk| chunk.can_shadow_sun())
.chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk))
.for_each(|chunk| drawer.draw_terrain_shadow(&chunk.opaque_model, &chunk.locals));
}
chunk_iter
.filter(|chunk| chunk.can_shadow_sun())
.chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk))
.for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.locals));
}
pub fn render_point_shadows<'a>(
&'a self,
drawer: &mut Drawer<'a>,
global: &GlobalModel,
(is_daylight, light_data): super::LightData,
pub fn chunks_for_point_shadows(
&self,
focus_pos: Vec3<f32>,
) {
) -> impl Clone
+ Iterator<
Item = (
&Model<pipelines::terrain::Vertex>,
&pipelines::terrain::BoundLocals,
),
> {
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
(e as i32).div_euclid(sz as i32)
});
let chunk_iter = Spiral2d::new()
.filter_map(|rpos| {
.filter_map(move |rpos| {
let pos = focus_chunk + rpos;
self.chunks.get(&pos)
})
@ -1317,35 +1315,27 @@ impl<V: RectRasterableVol> Terrain<V> {
//
// NOTE: We don't bother retaining chunks unless they cast sun shadows, so we
// don't use `shadow_chunks` here.
light_data.iter().take(1).for_each(|_light| {
drawer.draw_point_shadow(
&global.point_light_matrices,
chunk_iter
.clone()
.filter(|chunk| chunk.can_shadow_point)
.map(|chunk| (&chunk.opaque_model, &chunk.locals)),
);
});
chunk_iter
.filter(|chunk| chunk.can_shadow_point)
.map(|chunk| (&chunk.opaque_model, &chunk.locals))
}
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>, focus_pos: Vec3<f32>) {
span!(_guard, "render", "Terrain::render");
let mut drawer = drawer.draw_terrain(&self.col_lights);
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
(e as i32).div_euclid(sz as i32)
});
let chunk_iter = Spiral2d::new()
Spiral2d::new()
.filter_map(|rpos| {
let pos = focus_chunk + rpos;
self.chunks.get(&pos).map(|c| (pos, c))
self.chunks.get(&pos)
})
.take(self.chunks.len());
for (_, chunk) in chunk_iter {
if chunk.visible.is_visible() {
drawer.draw_terrain(&chunk.opaque_model, &chunk.locals, &self.col_lights)
}
}
.take(self.chunks.len())
.filter(|chunk| chunk.visible.is_visible())
.for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.locals));
}
pub fn render_translucent<'a>(
@ -1373,8 +1363,11 @@ impl<V: RectRasterableVol> Terrain<V> {
span!(guard, "Terrain sprites");
let chunk_size = V::RECT_SIZE.map(|e| e as f32);
let chunk_mag = (chunk_size * (f32::consts::SQRT_2 * 0.5)).magnitude_squared();
for (pos, chunk) in chunk_iter.clone() {
if chunk.visible.is_visible() {
let mut sprite_drawer = drawer.draw_sprites(&self.sprite_col_lights);
chunk_iter
.clone()
.filter(|(_, c)| c.visible.is_visible())
.for_each(|(pos, chunk)| {
let sprite_low_detail_distance = sprite_render_distance * 0.75;
let sprite_mid_detail_distance = sprite_render_distance * 0.5;
let sprite_hid_detail_distance = sprite_render_distance * 0.35;
@ -1396,6 +1389,8 @@ impl<V: RectRasterableVol> Terrain<V> {
chunk_center + chunk_size.x * 0.5 - chunk_size.y * 0.5,
));
if focus_dist_sqrd < sprite_render_distance.powi(2) {
// TODO: skip if sprite_instances is empty
let mut chunk_sprite_drawer = sprite_drawer.in_chunk(&chunk.locals);
for (kind, instances) in (&chunk.sprite_instances).into_iter() {
let SpriteData { model, locals, .. } = if kind
.0
@ -1417,24 +1412,17 @@ impl<V: RectRasterableVol> Terrain<V> {
&self.sprite_data[&kind][4]
};
drawer.draw_sprite(
model,
instances,
&chunk.locals,
locals,
&self.sprite_col_lights,
);
chunk_sprite_drawer.draw(model, instances, locals);
}
}
}
}
});
drop(sprite_drawer);
drop(guard);
// Translucent
span!(guard, "Fluid chunks");
let mut fluid_drawer = drawer.draw_fluid(&self.waves);
chunk_iter
.clone()
.filter(|(_, chunk)| chunk.visible.is_visible())
.filter_map(|(_, chunk)| {
chunk

View File

@ -1318,34 +1318,9 @@ impl PlayState for SessionState {
particles_enabled: settings.graphics.particles_enabled,
is_aiming: self.is_aiming,
};
drawer.shadow_pass().map(|mut drawer| {
self.scene.render_terrain_shadows(
&mut drawer,
client.state(),
client.entity(),
client.get_tick(),
&scene_data,
);
self.scene.render_figure_shadows(
&mut drawer,
client.state(),
client.entity(),
client.get_tick(),
&scene_data,
);
});
self.scene.render_point_shadows(
&mut drawer,
client.state(),
client.entity(),
client.get_tick(),
&scene_data,
);
self.scene.render(
&mut drawer.first_pass(),
&mut drawer,
client.state(),
client.entity(),
client.get_tick(),