dynamic uniform offsets
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::texture::{DitherTextures, FlowmapTexture};
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
use super::types::Uniforms;
|
||||
use super::Renderer;
|
||||
|
||||
impl Renderer
|
||||
@@ -24,7 +26,11 @@ impl Renderer
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: uniform_buffer.as_entire_binding(),
|
||||
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||
buffer: uniform_buffer,
|
||||
offset: 0,
|
||||
size: NonZeroU64::new(std::mem::size_of::<Uniforms>() as u64),
|
||||
}),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
|
||||
@@ -102,32 +102,31 @@ impl DebugOverlay
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let pipeline_snow_light =
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Snow Light Debug Pipeline"),
|
||||
layout: Some(&snow_light_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[ScreenVertex::desc()],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: Some("fs_snow_light"),
|
||||
targets: &[Some(color_target)],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
cull_mode: None,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let pipeline_snow_light = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Snow Light Debug Pipeline"),
|
||||
layout: Some(&snow_light_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[ScreenVertex::desc()],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: Some("fs_snow_light"),
|
||||
targets: &[Some(color_target)],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
cull_mode: None,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
pipeline_shadow,
|
||||
|
||||
@@ -6,12 +6,19 @@ mod types;
|
||||
|
||||
pub use types::{DrawCall, Pipeline, Spotlight, SpotlightRaw, Uniforms, MAX_SPOTLIGHTS};
|
||||
|
||||
use crate::entity::EntityHandle;
|
||||
|
||||
use crate::debug::DebugMode;
|
||||
use crate::postprocess::{create_blit_pipeline, create_fullscreen_quad, LowResFramebuffer};
|
||||
use crate::texture::{DitherTextures, FlowmapTexture};
|
||||
use pipeline::{create_debug_lines_pipeline, create_main_pipeline, create_snow_clipmap_pipeline,
|
||||
create_wireframe_pipeline};
|
||||
use pipeline::{
|
||||
create_debug_lines_pipeline, create_main_pipeline, create_snow_clipmap_pipeline,
|
||||
create_wireframe_pipeline,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
const MAX_DRAW_CALLS: usize = 64;
|
||||
|
||||
pub struct Renderer
|
||||
{
|
||||
@@ -62,6 +69,8 @@ pub struct Renderer
|
||||
|
||||
snow_light_accumulation: Option<crate::snow_light::SnowLightAccumulation>,
|
||||
snow_light_bound: bool,
|
||||
|
||||
pub selected_entity: Option<EntityHandle>,
|
||||
}
|
||||
|
||||
impl Renderer
|
||||
@@ -90,8 +99,9 @@ impl Renderer
|
||||
.await
|
||||
.map_err(|_| "Failed to find adapter")?;
|
||||
|
||||
let wireframe_supported =
|
||||
adapter.features().contains(wgpu::Features::POLYGON_MODE_LINE);
|
||||
let wireframe_supported = adapter
|
||||
.features()
|
||||
.contains(wgpu::Features::POLYGON_MODE_LINE);
|
||||
let required_features = if wireframe_supported
|
||||
{
|
||||
wgpu::Features::POLYGON_MODE_LINE
|
||||
@@ -129,7 +139,7 @@ impl Renderer
|
||||
|
||||
let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Uniform Buffer"),
|
||||
size: std::mem::size_of::<Uniforms>() as wgpu::BufferAddress,
|
||||
size: (std::mem::size_of::<Uniforms>() * MAX_DRAW_CALLS) as wgpu::BufferAddress,
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
@@ -306,8 +316,8 @@ impl Renderer
|
||||
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: NonZeroU64::new(std::mem::size_of::<Uniforms>() as u64),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
@@ -463,15 +473,22 @@ impl Renderer
|
||||
|
||||
let wireframe_pipeline = if wireframe_supported
|
||||
{
|
||||
Some(create_wireframe_pipeline(&device, config.format, &bind_group_layout))
|
||||
Some(create_wireframe_pipeline(
|
||||
&device,
|
||||
config.format,
|
||||
&bind_group_layout,
|
||||
))
|
||||
}
|
||||
else
|
||||
{
|
||||
None
|
||||
};
|
||||
|
||||
let debug_lines_pipeline =
|
||||
Some(create_debug_lines_pipeline(&device, config.format, &bind_group_layout));
|
||||
let debug_lines_pipeline = Some(create_debug_lines_pipeline(
|
||||
&device,
|
||||
config.format,
|
||||
&bind_group_layout,
|
||||
));
|
||||
|
||||
let debug_overlay = Some(debug_overlay::DebugOverlay::new(&device, config.format));
|
||||
|
||||
@@ -533,6 +550,7 @@ impl Renderer
|
||||
dummy_snow_light_sampler,
|
||||
snow_light_accumulation: None,
|
||||
snow_light_bound: false,
|
||||
selected_entity: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -585,6 +603,9 @@ impl Renderer
|
||||
label: Some("Render Encoder"),
|
||||
});
|
||||
|
||||
let uniform_size = std::mem::size_of::<Uniforms>() as u64;
|
||||
let mut uniform_slot: u64 = 0;
|
||||
|
||||
for (i, draw_call) in draw_calls.iter().enumerate()
|
||||
{
|
||||
let uniforms = Uniforms::new(
|
||||
@@ -603,8 +624,15 @@ impl Renderer
|
||||
&self.spotlights,
|
||||
debug_mode.as_u32(),
|
||||
);
|
||||
self.queue
|
||||
.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[uniforms]));
|
||||
|
||||
let offset = uniform_slot * uniform_size;
|
||||
uniform_slot += 1;
|
||||
|
||||
self.queue.write_buffer(
|
||||
&self.uniform_buffer,
|
||||
offset,
|
||||
bytemuck::cast_slice(&[uniforms]),
|
||||
);
|
||||
|
||||
{
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
@@ -660,7 +688,7 @@ impl Renderer
|
||||
.unwrap_or(&self.standard_pipeline),
|
||||
};
|
||||
render_pass.set_pipeline(pipeline);
|
||||
render_pass.set_bind_group(0, &self.bind_group, &[]);
|
||||
render_pass.set_bind_group(0, &self.bind_group, &[offset as u32]);
|
||||
|
||||
if let Some(ref displacement_bind_group) = draw_call.displacement_bind_group
|
||||
{
|
||||
@@ -686,7 +714,10 @@ impl Renderer
|
||||
{
|
||||
for draw_call in draw_calls.iter()
|
||||
{
|
||||
if matches!(draw_call.pipeline, Pipeline::SnowClipmap | Pipeline::DebugLines)
|
||||
if matches!(
|
||||
draw_call.pipeline,
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -707,9 +738,11 @@ impl Renderer
|
||||
&self.spotlights,
|
||||
4,
|
||||
);
|
||||
let wire_offset = uniform_slot * uniform_size;
|
||||
uniform_slot += 1;
|
||||
self.queue.write_buffer(
|
||||
&self.uniform_buffer,
|
||||
0,
|
||||
wire_offset,
|
||||
bytemuck::cast_slice(&[uniforms]),
|
||||
);
|
||||
|
||||
@@ -742,7 +775,7 @@ impl Renderer
|
||||
});
|
||||
|
||||
wire_pass.set_pipeline(wireframe_pipeline);
|
||||
wire_pass.set_bind_group(0, &self.bind_group, &[]);
|
||||
wire_pass.set_bind_group(0, &self.bind_group, &[wire_offset as u32]);
|
||||
wire_pass.set_vertex_buffer(0, draw_call.vertex_buffer.slice(..));
|
||||
|
||||
if let Some(ref instance_buffer) = draw_call.instance_buffer
|
||||
@@ -764,6 +797,99 @@ impl Renderer
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(selected) = self.selected_entity
|
||||
{
|
||||
if let Some(ref wireframe_pipeline) = self.wireframe_pipeline
|
||||
{
|
||||
for draw_call in draw_calls.iter()
|
||||
{
|
||||
if draw_call.entity != Some(selected)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
draw_call.pipeline,
|
||||
Pipeline::SnowClipmap | Pipeline::DebugLines
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let uniforms = Uniforms::new(
|
||||
draw_call.model,
|
||||
*view,
|
||||
*projection,
|
||||
&light_view_projections,
|
||||
camera_position,
|
||||
player_position,
|
||||
self.terrain_height_scale,
|
||||
time,
|
||||
self.shadow_bias,
|
||||
draw_call.tile_scale,
|
||||
draw_call.enable_dissolve,
|
||||
draw_call.enable_snow_light,
|
||||
&self.spotlights,
|
||||
4,
|
||||
);
|
||||
let sel_offset = uniform_slot * uniform_size;
|
||||
uniform_slot += 1;
|
||||
self.queue.write_buffer(
|
||||
&self.uniform_buffer,
|
||||
sel_offset,
|
||||
bytemuck::cast_slice(&[uniforms]),
|
||||
);
|
||||
|
||||
{
|
||||
let mut sel_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Selection Wireframe Pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &self.framebuffer.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
depth_slice: None,
|
||||
})],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &self.framebuffer.depth_view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: wgpu::StoreOp::Store,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
sel_pass.set_pipeline(wireframe_pipeline);
|
||||
sel_pass.set_bind_group(0, &self.bind_group, &[sel_offset as u32]);
|
||||
sel_pass.set_vertex_buffer(0, draw_call.vertex_buffer.slice(..));
|
||||
|
||||
if let Some(ref instance_buffer) = draw_call.instance_buffer
|
||||
{
|
||||
sel_pass.set_vertex_buffer(1, instance_buffer.slice(..));
|
||||
}
|
||||
|
||||
sel_pass.set_index_buffer(
|
||||
draw_call.index_buffer.slice(..),
|
||||
wgpu::IndexFormat::Uint32,
|
||||
);
|
||||
sel_pass.draw_indexed(
|
||||
0..draw_call.num_indices,
|
||||
0,
|
||||
0..draw_call.num_instances,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if debug_mode == DebugMode::ShadowMap
|
||||
{
|
||||
if let Some(ref overlay) = self.debug_overlay
|
||||
@@ -1074,3 +1200,12 @@ pub fn update_spotlights(spotlights: Vec<Spotlight>)
|
||||
renderer.spotlights = spotlights;
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_selected_entity(entity: Option<EntityHandle>)
|
||||
{
|
||||
GLOBAL_RENDERER.with(|r| {
|
||||
let mut renderer = r.borrow_mut();
|
||||
let renderer = renderer.as_mut().expect("Renderer not set");
|
||||
renderer.selected_entity = entity;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use glam::Mat4;
|
||||
|
||||
use crate::entity::EntityHandle;
|
||||
|
||||
pub const MAX_SPOTLIGHTS: usize = 4;
|
||||
|
||||
#[repr(C)]
|
||||
@@ -156,4 +158,5 @@ pub struct DrawCall
|
||||
pub enable_dissolve: bool,
|
||||
pub enable_snow_light: bool,
|
||||
pub displacement_bind_group: Option<wgpu::BindGroup>,
|
||||
pub entity: Option<EntityHandle>,
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ pub fn render_system(world: &World) -> Vec<DrawCall>
|
||||
enable_dissolve: mesh_component.enable_dissolve,
|
||||
enable_snow_light: mesh_component.enable_snow_light,
|
||||
displacement_bind_group: None,
|
||||
entity: Some(entity),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
|
||||
Reference in New Issue
Block a user