140 lines
4.5 KiB
Rust
140 lines
4.5 KiB
Rust
use glam::Mat4;
|
|
|
|
use super::types::{DrawCall, Uniforms, MAX_SPOTLIGHTS};
|
|
use super::Renderer;
|
|
|
|
impl Renderer
|
|
{
|
|
pub(super) fn render_shadow_pass(
|
|
&mut self,
|
|
draw_calls: &[DrawCall],
|
|
light_view_projections: &[Mat4],
|
|
player_position: glam::Vec3,
|
|
time: f32,
|
|
)
|
|
{
|
|
let spotlight_count = self.spotlights.len().min(MAX_SPOTLIGHTS);
|
|
|
|
for layer in 0..spotlight_count
|
|
{
|
|
let shadow_uniforms = Uniforms::new(
|
|
Mat4::IDENTITY,
|
|
Mat4::IDENTITY,
|
|
light_view_projections[layer],
|
|
light_view_projections,
|
|
glam::Vec3::ZERO,
|
|
player_position,
|
|
self.terrain_height_scale,
|
|
time,
|
|
self.shadow_bias,
|
|
2.0,
|
|
false,
|
|
false,
|
|
&self.spotlights,
|
|
);
|
|
self.queue.write_buffer(
|
|
&self.uniform_buffer,
|
|
0,
|
|
bytemuck::cast_slice(&[shadow_uniforms]),
|
|
);
|
|
|
|
let layer_view = self
|
|
.shadow_map_texture
|
|
.create_view(&wgpu::TextureViewDescriptor {
|
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
|
base_array_layer: layer as u32,
|
|
array_layer_count: Some(1),
|
|
..Default::default()
|
|
});
|
|
|
|
let mut encoder = self
|
|
.device
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
label: Some("Shadow Pass Encoder"),
|
|
});
|
|
|
|
{
|
|
let mut shadow_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
label: Some("Shadow Pass"),
|
|
color_attachments: &[],
|
|
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
|
view: &layer_view,
|
|
depth_ops: Some(wgpu::Operations {
|
|
load: wgpu::LoadOp::Clear(1.0),
|
|
store: wgpu::StoreOp::Store,
|
|
}),
|
|
stencil_ops: None,
|
|
}),
|
|
timestamp_writes: None,
|
|
occlusion_query_set: None,
|
|
});
|
|
|
|
shadow_pass.set_pipeline(
|
|
self.shadow_pipeline
|
|
.as_ref()
|
|
.expect("shadow pipeline missing"),
|
|
);
|
|
shadow_pass.set_bind_group(
|
|
0,
|
|
self.shadow_bind_group
|
|
.as_ref()
|
|
.expect("shadow bind group missing"),
|
|
&[],
|
|
);
|
|
|
|
for draw_call in draw_calls.iter()
|
|
{
|
|
shadow_pass.set_vertex_buffer(0, draw_call.vertex_buffer.slice(..));
|
|
|
|
if let Some(ref instance_buffer) = draw_call.instance_buffer
|
|
{
|
|
shadow_pass.set_vertex_buffer(1, instance_buffer.slice(..));
|
|
}
|
|
|
|
shadow_pass.set_index_buffer(
|
|
draw_call.index_buffer.slice(..),
|
|
wgpu::IndexFormat::Uint32,
|
|
);
|
|
shadow_pass.draw_indexed(
|
|
0..draw_call.num_indices,
|
|
0,
|
|
0..draw_call.num_instances,
|
|
);
|
|
}
|
|
}
|
|
|
|
self.queue.submit(std::iter::once(encoder.finish()));
|
|
}
|
|
}
|
|
|
|
pub(super) fn calculate_light_view_projections(&self) -> Vec<Mat4>
|
|
{
|
|
self.spotlights
|
|
.iter()
|
|
.take(MAX_SPOTLIGHTS)
|
|
.map(|spotlight| {
|
|
let light_position = spotlight.position;
|
|
let light_target = spotlight.position + spotlight.direction;
|
|
|
|
let up_vector = if spotlight.direction.y.abs() > 0.99
|
|
{
|
|
glam::Vec3::Z
|
|
}
|
|
else
|
|
{
|
|
glam::Vec3::Y
|
|
};
|
|
|
|
let light_view = Mat4::look_at_rh(light_position, light_target, up_vector);
|
|
|
|
let fov = spotlight.outer_angle * 2.0;
|
|
let near = 0.1;
|
|
let far = 150.0;
|
|
let light_projection = Mat4::perspective_rh(fov, 1.0, near, far);
|
|
|
|
light_projection * light_view
|
|
})
|
|
.collect()
|
|
}
|
|
}
|