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 { 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() } }