(&self, path: &str, cascade: usize)
| 12980 | |
| 12981 | #[cfg(not(target_arch = "wasm32"))] |
| 12982 | pub fn dump_shadow_cascade(&self, path: &str, cascade: usize) { |
| 12983 | let cascade = cascade.min(crate::shadows::NUM_CASCADES - 1); |
| 12984 | let size = crate::shadows::CASCADE_MAP_SIZE; |
| 12985 | let bytes_per_pixel = 4u32; // Depth32Float = 4 bytes |
| 12986 | let unpadded_bpr = size * bytes_per_pixel; |
| 12987 | let padded_bpr = (unpadded_bpr + 255) & !255; |
| 12988 | let buf_size = (padded_bpr * size) as u64; |
| 12989 | |
| 12990 | let staging = self.device.create_buffer(&wgpu::BufferDescriptor { |
| 12991 | label: Some("shadow_dump_staging"), |
| 12992 | size: buf_size, |
| 12993 | usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, |
| 12994 | mapped_at_creation: false, |
| 12995 | }); |
| 12996 | |
| 12997 | let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { |
| 12998 | label: Some("shadow_dump_encoder"), |
| 12999 | }); |
| 13000 | |
| 13001 | encoder.copy_texture_to_buffer( |
| 13002 | wgpu::TexelCopyTextureInfo { |
| 13003 | texture: &self.shadow_map.depth_textures[cascade], |
| 13004 | mip_level: 0, |
| 13005 | origin: wgpu::Origin3d::ZERO, |
| 13006 | aspect: wgpu::TextureAspect::DepthOnly, |
| 13007 | }, |
| 13008 | wgpu::TexelCopyBufferInfo { |
| 13009 | buffer: &staging, |
| 13010 | layout: wgpu::TexelCopyBufferLayout { |
| 13011 | offset: 0, |
| 13012 | bytes_per_row: Some(padded_bpr), |
| 13013 | rows_per_image: Some(size), |
| 13014 | }, |
| 13015 | }, |
| 13016 | wgpu::Extent3d { width: size, height: size, depth_or_array_layers: 1 }, |
| 13017 | ); |
| 13018 | |
| 13019 | self.queue.submit(std::iter::once(encoder.finish())); |
| 13020 | |
| 13021 | let slice = staging.slice(..); |
| 13022 | let (tx, rx) = std::sync::mpsc::channel(); |
| 13023 | slice.map_async(wgpu::MapMode::Read, move |r| { let _ = tx.send(r); }); |
| 13024 | let _ = self.device.poll(wgpu::PollType::Wait { submission_index: None, timeout: None }); |
| 13025 | |
| 13026 | if let Ok(Ok(())) = rx.recv() { |
| 13027 | let data = slice.get_mapped_range(); |
| 13028 | // Convert f32 depth values to grayscale RGB |
| 13029 | let mut rgb = Vec::with_capacity((size * size * 3) as usize); |
| 13030 | for row in 0..size { |
| 13031 | let row_start = (row * padded_bpr) as usize; |
| 13032 | for col in 0..size { |
| 13033 | let offset = row_start + (col * bytes_per_pixel) as usize; |
| 13034 | let depth = f32::from_le_bytes([ |
| 13035 | data[offset], data[offset+1], data[offset+2], data[offset+3], |
| 13036 | ]); |
| 13037 | // depth 0 = near (white), depth 1 = far/clear (black) |
| 13038 | let gray = ((1.0 - depth.clamp(0.0, 1.0)) * 255.0) as u8; |
| 13039 | rgb.push(gray); |
no test coverage detected