Implement Shadows #24
|
@ -8,9 +8,12 @@ use tracing::{debug, warn};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
use crate::render::{
|
use crate::render::{
|
||||||
graph::{Node, NodeDesc, NodeType},
|
graph::{Node, NodeDesc, NodeType, SlotAttribute, SlotValue},
|
||||||
light::directional::DirectionalLight,
|
light::directional::DirectionalLight,
|
||||||
resource::{FragmentState, PipelineDescriptor, RenderPipeline, RenderPipelineDescriptor, Shader, VertexState},
|
resource::{
|
||||||
|
FragmentState, PipelineDescriptor, RenderPipeline, RenderPipelineDescriptor, Shader,
|
||||||
|
VertexState,
|
||||||
|
},
|
||||||
transform_buffer_storage::TransformBuffers,
|
transform_buffer_storage::TransformBuffers,
|
||||||
vertex::Vertex,
|
vertex::Vertex,
|
||||||
};
|
};
|
||||||
|
@ -19,14 +22,18 @@ use super::{MeshBufferStorage, RenderAssets, RenderMeshes};
|
||||||
|
|
||||||
const SHADOW_SIZE: glam::UVec2 = glam::UVec2::new(1024, 1024);
|
const SHADOW_SIZE: glam::UVec2 = glam::UVec2::new(1024, 1024);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
||||||
|
pub enum ShadowMapsPassSlots {
|
||||||
|
ShadowAtlasTexture,
|
||||||
|
ShadowAtlasTextureView,
|
||||||
|
ShadowAtlasSampler,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
||||||
pub struct ShadowMapsPassLabel;
|
pub struct ShadowMapsPassLabel;
|
||||||
|
|
||||||
struct LightDepthMap {
|
struct LightDepthMap {
|
||||||
light_projection_buffer: wgpu::Buffer,
|
light_projection_buffer: wgpu::Buffer,
|
||||||
texture: wgpu::Texture,
|
|
||||||
view: wgpu::TextureView,
|
|
||||||
sampler: wgpu::Sampler,
|
|
||||||
bindgroup: wgpu::BindGroup,
|
bindgroup: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,39 +48,37 @@ pub struct ShadowMapsPass {
|
||||||
render_meshes: Option<ResourceData>,
|
render_meshes: Option<ResourceData>,
|
||||||
mesh_buffers: Option<ResourceData>,
|
mesh_buffers: Option<ResourceData>,
|
||||||
pipeline: Option<RenderPipeline>,
|
pipeline: Option<RenderPipeline>,
|
||||||
|
|
||||||
|
/// The depth map atlas texture
|
||||||
|
atlas_texture: Rc<wgpu::Texture>,
|
||||||
|
/// The depth map atlas texture view
|
||||||
|
atlas_view: Arc<wgpu::TextureView>,
|
||||||
|
/// The depth map atlas sampler
|
||||||
|
atlas_sampler: Rc<wgpu::Sampler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShadowMapsPass {
|
impl ShadowMapsPass {
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
let bgl = Arc::new(device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bgl = Arc::new(
|
||||||
label: Some("shadows_bgl"),
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
entries: &[wgpu::BindGroupLayoutEntry {
|
label: Some("bgl_shadows_light_projection"),
|
||||||
binding: 0,
|
entries: &[wgpu::BindGroupLayoutEntry {
|
||||||
visibility: wgpu::ShaderStages::VERTEX,
|
binding: 0,
|
||||||
ty: wgpu::BindingType::Buffer {
|
visibility: wgpu::ShaderStages::VERTEX,
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
ty: wgpu::BindingType::Buffer {
|
||||||
has_dynamic_offset: false,
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
min_binding_size: Some(
|
has_dynamic_offset: false,
|
||||||
NonZeroU64::new(mem::size_of::<glam::Mat4>() as _).unwrap(),
|
min_binding_size: Some(
|
||||||
),
|
NonZeroU64::new(mem::size_of::<glam::Mat4>() as _).unwrap(),
|
||||||
},
|
),
|
||||||
count: None,
|
},
|
||||||
}],
|
count: None,
|
||||||
}));
|
}],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
|
||||||
bgl,
|
|
||||||
depth_maps: Default::default(),
|
|
||||||
transform_buffers: None,
|
|
||||||
render_meshes: None,
|
|
||||||
mesh_buffers: None,
|
|
||||||
pipeline: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_depth_map(&mut self, device: &wgpu::Device, entity: Entity, light_pos: Transform) {
|
|
||||||
let tex = device.create_texture(&wgpu::TextureDescriptor {
|
let tex = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
label: Some("texture_shadow_map_directional_light"),
|
label: Some("texture_shadow_map_atlas"),
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: SHADOW_SIZE.x,
|
width: SHADOW_SIZE.x,
|
||||||
height: SHADOW_SIZE.y,
|
height: SHADOW_SIZE.y,
|
||||||
|
@ -93,7 +98,7 @@ impl ShadowMapsPass {
|
||||||
});
|
});
|
||||||
|
|
||||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
label: Some("sampler_light_depth_map"),
|
label: Some("sampler_shadow_map_atlas"),
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||||
|
@ -104,17 +109,29 @@ impl ShadowMapsPass {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
bgl,
|
||||||
|
depth_maps: Default::default(),
|
||||||
|
transform_buffers: None,
|
||||||
|
render_meshes: None,
|
||||||
|
mesh_buffers: None,
|
||||||
|
pipeline: None,
|
||||||
|
|
||||||
|
atlas_sampler: Rc::new(sampler),
|
||||||
|
atlas_texture: Rc::new(tex),
|
||||||
|
atlas_view: Arc::new(view),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_depth_map(&mut self, device: &wgpu::Device, entity: Entity, light_pos: Transform) {
|
||||||
const NEAR_PLANE: f32 = 0.1;
|
const NEAR_PLANE: f32 = 0.1;
|
||||||
const FAR_PLANE: f32 = 80.0;
|
const FAR_PLANE: f32 = 80.0;
|
||||||
|
|
||||||
let ortho_proj =
|
let ortho_proj =
|
||||||
glam::Mat4::orthographic_rh_gl(-20.0, 20.0, -20.0, 20.0, NEAR_PLANE, FAR_PLANE);
|
glam::Mat4::orthographic_rh_gl(-20.0, 20.0, -20.0, 20.0, NEAR_PLANE, FAR_PLANE);
|
||||||
|
|
||||||
let look_view = glam::Mat4::look_to_rh(
|
let look_view =
|
||||||
light_pos.translation,
|
glam::Mat4::look_to_rh(light_pos.translation, light_pos.forward(), light_pos.up());
|
||||||
light_pos.forward(),
|
|
||||||
light_pos.up()
|
|
||||||
);
|
|
||||||
|
|
||||||
let light_proj = OPENGL_TO_WGPU_MATRIX * (ortho_proj * look_view);
|
let light_proj = OPENGL_TO_WGPU_MATRIX * (ortho_proj * look_view);
|
||||||
|
|
||||||
|
@ -142,9 +159,6 @@ impl ShadowMapsPass {
|
||||||
entity,
|
entity,
|
||||||
LightDepthMap {
|
LightDepthMap {
|
||||||
light_projection_buffer,
|
light_projection_buffer,
|
||||||
texture: tex,
|
|
||||||
view,
|
|
||||||
sampler,
|
|
||||||
bindgroup: bg,
|
bindgroup: bg,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -168,7 +182,27 @@ impl Node for ShadowMapsPass {
|
||||||
&mut self,
|
&mut self,
|
||||||
graph: &mut crate::render::graph::RenderGraph,
|
graph: &mut crate::render::graph::RenderGraph,
|
||||||
) -> crate::render::graph::NodeDesc {
|
) -> crate::render::graph::NodeDesc {
|
||||||
NodeDesc::new(NodeType::Render, None, vec![])
|
let mut node = NodeDesc::new(NodeType::Render, None, vec![]);
|
||||||
|
|
||||||
|
node.add_texture_slot(
|
||||||
|
ShadowMapsPassSlots::ShadowAtlasTexture,
|
||||||
|
SlotAttribute::Output,
|
||||||
|
Some(SlotValue::Texture(self.atlas_texture.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
node.add_texture_view_slot(
|
||||||
|
ShadowMapsPassSlots::ShadowAtlasTextureView,
|
||||||
|
SlotAttribute::Output,
|
||||||
|
Some(SlotValue::TextureView(self.atlas_view.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
node.add_sampler_slot(
|
||||||
|
ShadowMapsPassSlots::ShadowAtlasSampler,
|
||||||
|
SlotAttribute::Output,
|
||||||
|
Some(SlotValue::Sampler(self.atlas_sampler.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(
|
fn prepare(
|
||||||
|
@ -201,10 +235,7 @@ impl Node for ShadowMapsPass {
|
||||||
&graph.device,
|
&graph.device,
|
||||||
&RenderPipelineDescriptor {
|
&RenderPipelineDescriptor {
|
||||||
label: Some("pipeline_shadows".into()),
|
label: Some("pipeline_shadows".into()),
|
||||||
layouts: vec![
|
layouts: vec![bgl, transforms],
|
||||||
bgl,
|
|
||||||
transforms,
|
|
||||||
],
|
|
||||||
push_constant_ranges: vec![],
|
push_constant_ranges: vec![],
|
||||||
vertex: VertexState {
|
vertex: VertexState {
|
||||||
module: shader.clone(),
|
module: shader.clone(),
|
||||||
|
@ -226,7 +257,7 @@ impl Node for ShadowMapsPass {
|
||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
multiview: None,
|
multiview: None,
|
||||||
}
|
},
|
||||||
));
|
));
|
||||||
/* */
|
/* */
|
||||||
}
|
}
|
||||||
|
@ -261,7 +292,7 @@ impl Node for ShadowMapsPass {
|
||||||
label: Some("pass_shadow_map"),
|
label: Some("pass_shadow_map"),
|
||||||
color_attachments: &[],
|
color_attachments: &[],
|
||||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||||
view: &dir_depth_map.view,
|
view: &self.atlas_view,
|
||||||
depth_ops: Some(wgpu::Operations {
|
depth_ops: Some(wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(1.0),
|
load: wgpu::LoadOp::Clear(1.0),
|
||||||
store: true,
|
store: true,
|
||||||
|
|
Loading…
Reference in New Issue