Load DEM texture

This commit is contained in:
Matthew Gordon 2024-11-22 20:20:06 -04:00
parent 8906f6e47a
commit a4503c3dbf
3 changed files with 148 additions and 38 deletions

View File

@ -1,7 +1,7 @@
use super::raster::Dem; use super::raster::Dem;
use { use {
bytemuck::{Pod, Zeroable}, bytemuck::{Pod, Zeroable},
std::{borrow::Cow, rc::Rc}, std::{borrow::Cow, num::NonZero, rc::Rc},
wgpu::util::DeviceExt, wgpu::util::DeviceExt,
}; };
@ -12,7 +12,8 @@ pub struct DemRenderer {
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer,
index_count: usize, index_count: usize,
uniforms: Uniforms, camera: Camera,
uniforms: UniformBufferManager,
animation_start: std::time::Instant, animation_start: std::time::Instant,
} }
@ -30,32 +31,27 @@ impl Vertex {
} }
} }
struct Uniforms { struct Camera {
projection_matrix: glam::Mat4, projection_matrix: glam::Mat4,
view_matrix: glam::Mat4, view_matrix: glam::Mat4,
buffer: wgpu::Buffer,
} }
impl Uniforms { impl Camera {
fn new(device: &wgpu::Device, aspect_ratio: f32) -> Self { fn new(device: &wgpu::Device, viewport_aspect_ratio: f32) -> Self {
let projection_matrix = let projection_matrix = glam::Mat4::perspective_rh(
glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, aspect_ratio, 1.0, 10000.0); std::f32::consts::FRAC_PI_4,
viewport_aspect_ratio,
1.0,
10000.0,
);
let view_matrix = glam::Mat4::look_at_rh(glam::Vec3::ZERO, glam::Vec3::ZERO, glam::Vec3::Z); let view_matrix = glam::Mat4::look_at_rh(glam::Vec3::ZERO, glam::Vec3::ZERO, glam::Vec3::Z);
let camera_matrix = projection_matrix * view_matrix;
let camera_matrix_ref: &[f32; 16] = camera_matrix.as_ref();
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: bytemuck::cast_slice(camera_matrix_ref),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
Self { Self {
projection_matrix, projection_matrix,
view_matrix, view_matrix,
buffer,
} }
} }
fn set_camera_position(&mut self, camera_position: glam::Vec3, camera_look_at: glam::Vec3) { fn set_position(&mut self, camera_position: glam::Vec3, camera_look_at: glam::Vec3) {
self.view_matrix = glam::Mat4::look_at_rh(camera_position, camera_look_at, glam::Vec3::Z); self.view_matrix = glam::Mat4::look_at_rh(camera_position, camera_look_at, glam::Vec3::Z);
} }
@ -64,14 +60,63 @@ impl Uniforms {
glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, ratio, 1.0, 10.0); glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, ratio, 1.0, 10.0);
} }
fn update_buffer(&self, queue: &wgpu::Queue) { fn get_matrix(&self) -> glam::Mat4 {
let camera_matrix = self.projection_matrix * self.view_matrix; self.projection_matrix * self.view_matrix
let camera_matrix_ref: &[f32; 16] = camera_matrix.as_ref(); }
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(camera_matrix_ref)) }
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
struct UniformBufferContents {
camera_matrix: [f32; 16],
dem_texture_size: [u32; 2],
}
// This struct is 72 bytes but WGSL expects the buffer size to be be a multiple
// of the alignment of the member with the largest alignment. The mat4x4<f32>
// type has a 16-byte alignment, so we round up to 16 * 5 = 80.
const UNIFORM_BUFFER_SIZE: u64 = 80;
struct UniformBufferManager {
cpu_buffer: UniformBufferContents,
gpu_buffer: wgpu::Buffer,
}
impl UniformBufferManager {
fn new(device: &wgpu::Device) -> Self {
let cpu_buffer = UniformBufferContents::zeroed();
let gpu_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Uniform Buffer"),
contents: &[0u8; UNIFORM_BUFFER_SIZE as usize],
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
Self {
cpu_buffer,
gpu_buffer,
}
} }
fn binding(&self) -> wgpu::BindingResource<'_> { fn set_camera_matrix(&mut self, camera_matrix: glam::Mat4) {
self.buffer.as_entire_binding() self.cpu_buffer
.camera_matrix
.clone_from_slice(&camera_matrix.to_cols_array())
}
fn set_dem_texture_size(&mut self, dem_texture_size: glam::UVec2) {
self.cpu_buffer
.dem_texture_size
.clone_from_slice(&dem_texture_size.to_array());
}
fn get_binding(&self) -> wgpu::BindingResource<'_> {
wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &self.gpu_buffer,
offset: 0,
size: NonZero::new(UNIFORM_BUFFER_SIZE),
})
}
fn update_buffer(&self, queue: &wgpu::Queue) {
queue.write_buffer(&self.gpu_buffer, 0, bytemuck::bytes_of(&self.cpu_buffer));
} }
} }
@ -80,6 +125,7 @@ impl DemRenderer {
source: Rc<Dem>, source: Rc<Dem>,
device: &wgpu::Device, device: &wgpu::Device,
surface_config: &wgpu::SurfaceConfiguration, surface_config: &wgpu::SurfaceConfiguration,
queue: &wgpu::Queue,
) -> Self { ) -> Self {
let (vertex_data, index_data) = create_vertices(&source); let (vertex_data, index_data) = create_vertices(&source);
@ -97,25 +143,67 @@ impl DemRenderer {
let index_count = index_data.len(); let index_count = index_data.len();
let uniforms = Uniforms::new( let (dem_texture_view, dem_texture_size) = {
let texture_size = wgpu::Extent3d {
width: source.num_cells_x,
height: source.num_cells_y,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dem Texture"),
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R16Uint,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::ImageCopyTexture {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
bytemuck::cast_slice(&source.grid[..]),
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(std::mem::size_of::<u16>() as u32 * source.num_cells_x),
rows_per_image: Some(source.num_cells_y),
},
texture_size,
);
(
texture.create_view(&wgpu::TextureViewDescriptor::default()),
glam::UVec2::new(source.num_cells_x, source.num_cells_y),
)
};
let camera = Camera::new(
device, device,
surface_config.width as f32 / surface_config.height as f32, surface_config.width as f32 / surface_config.height as f32,
); );
let mut uniforms = UniformBufferManager::new(device);
uniforms.set_dem_texture_size(dem_texture_size);
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None, label: None,
entries: &[ entries: &[
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
visibility: wgpu::ShaderStages::VERTEX, visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer { ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform, ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false, has_dynamic_offset: false,
min_binding_size: wgpu::BufferSize::new(64), min_binding_size: wgpu::BufferSize::new(UNIFORM_BUFFER_SIZE),
}, },
count: None, count: None,
}, },
/*wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 1, binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT, visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture { ty: wgpu::BindingType::Texture {
@ -124,16 +212,22 @@ impl DemRenderer {
view_dimension: wgpu::TextureViewDimension::D2, view_dimension: wgpu::TextureViewDimension::D2,
}, },
count: None, count: None,
},*/ },
], ],
}); });
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout, layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry { entries: &[
wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: uniforms.binding(), resource: uniforms.get_binding(),
}], },
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&dem_texture_view),
},
],
label: Some("DemRendererBindGroup"), label: Some("DemRendererBindGroup"),
}); });
@ -190,6 +284,7 @@ impl DemRenderer {
index_buffer, index_buffer,
index_count, index_count,
animation_start: std::time::Instant::now(), animation_start: std::time::Instant::now(),
camera,
uniforms, uniforms,
} }
} }
@ -198,13 +293,14 @@ impl DemRenderer {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("DemRendererCommandEncoder"), label: Some("DemRendererCommandEncoder"),
}); });
self.uniforms.set_camera_position( self.camera.set_position(
get_animated_camera_position( get_animated_camera_position(
self.animation_start.elapsed(), self.animation_start.elapsed(),
self.get_max_dem_dimension(), self.get_max_dem_dimension(),
), ),
self.get_dem_centre(), self.get_dem_centre(),
); );
self.uniforms.set_camera_matrix(self.camera.get_matrix());
self.uniforms.update_buffer(queue); self.uniforms.update_buffer(queue);
{ {
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {

View File

@ -1,21 +1,34 @@
struct VertexOutput { struct VertexOutput {
@location(0) test: vec2<f32>,
@builtin(position) position: vec4<f32>, @builtin(position) position: vec4<f32>,
}; };
@group(0) struct Uniforms {
@binding(0) transform: mat4x4<f32>,
var<uniform> transform: mat4x4<f32>; dem_texture_size: vec2<u32>
}
@group(0) @binding(0)
var<uniform> uniforms: Uniforms;
@group(0) @binding(1)
var dem_texture: texture_2d<u32>;
@vertex @vertex
fn vs_main( fn vs_main(
@location(0) position: vec4<f32>, @location(0) position: vec4<f32>,
) -> VertexOutput { ) -> VertexOutput {
var result: VertexOutput; var result: VertexOutput;
result.position = transform * position; result.position = uniforms.transform * position;
result.test = position.xy;
return result; return result;
} }
@fragment @fragment
fn fs_solid(vertex: VertexOutput) -> @location(0) vec4<f32> { fn fs_solid(vertex: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 1.0, 1.0, 1.0); let texture_index = vec2<i32>(fract(abs(vertex.test)/500.0)*vec2<f32>(uniforms.dem_texture_size));
let v_i = textureLoad(dem_texture, texture_index, 0).r;
let v = f32(v_i) / 65535.0;
return vec4<f32>(v, v, 1.0, 1.0);
} }

View File

@ -153,6 +153,7 @@ impl MvuApp<Model> for App {
dem.clone(), dem.clone(),
&context.device, &context.device,
&context.config, &context.config,
&context.queue,
)) ))
} }
} }