Add non-working raycasting code

Implemented basic raycasting but it doesn't work; I'll check this in and
then add GPU unit tests.
This commit is contained in:
Matthew Gordon 2024-11-29 20:28:20 -04:00
parent 5e3b97ed61
commit f7603661c1
2 changed files with 151 additions and 46 deletions

View File

@ -69,13 +69,16 @@ impl Camera {
#[derive(Clone, Copy, Pod, Zeroable)]
struct UniformBufferContents {
camera_matrix: [f32; 16],
dem_texture_size: [u32; 2],
dembvh_texture_size: [u32; 2],
camera_position: [f32; 4],
dem_min_corner: [f32; 2],
dem_cell_size: [f32; 2],
dem_z_range: [f32; 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;
// 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 this value may be rounded up from the actual size of
// UniformBufferContents.
const UNIFORM_BUFFER_SIZE: u64 = 112;
struct UniformBufferManager {
cpu_buffer: UniformBufferContents,
@ -102,16 +105,28 @@ impl UniformBufferManager {
.clone_from_slice(&camera_matrix.to_cols_array())
}
fn set_dem_texture_size(&mut self, dem_texture_size: glam::UVec2) {
fn set_camera_position(&mut self, camera_position: glam::Vec4) {
self.cpu_buffer
.dem_texture_size
.clone_from_slice(&dem_texture_size.to_array());
.camera_position
.clone_from_slice(&camera_position.to_array())
}
fn set_dembvh_texture_size(&mut self, dembvh_texture_size: glam::UVec2) {
fn set_dem_min_corner(&mut self, value: glam::Vec2) {
self.cpu_buffer
.dembvh_texture_size
.clone_from_slice(&dembvh_texture_size.to_array());
.dem_min_corner
.clone_from_slice(&value.to_array());
}
fn set_dem_cell_size(&mut self, value: glam::Vec2) {
self.cpu_buffer
.dem_cell_size
.clone_from_slice(&value.to_array());
}
fn set_dem_z_range(&mut self, value: glam::Vec2) {
self.cpu_buffer
.dem_z_range
.clone_from_slice(&value.to_array());
}
fn get_binding(&self) -> wgpu::BindingResource<'_> {
@ -150,15 +165,19 @@ impl DemRenderer {
let index_count = index_data.len();
let (dem_texture_view, dem_texture_size) = load_dem_texture(&source, device, queue);
let (dembvh_texture_view, dembvh_texture_size) =
create_dembvh_texture(&source, device, queue);
let dem_texture_view = load_dem_texture(&source, device, queue);
let dembvh_texture_view = create_dembvh_texture(&source, device, queue);
let camera = Camera::new(surface_config.width as f32 / surface_config.height as f32);
let mut uniforms = UniformBufferManager::new(device);
uniforms.set_dem_texture_size(dem_texture_size);
uniforms.set_dembvh_texture_size(dembvh_texture_size);
uniforms.set_dem_min_corner(glam::Vec2::new(source.x_min, source.y_min));
uniforms.set_dem_cell_size(
glam::Vec2::new(source.x_max, source.y_max)
- glam::Vec2::new(source.x_min, source.y_min)
/ glam::Vec2::new(source.num_cells_x as f32, source.num_cells_y as f32),
);
uniforms.set_dem_z_range(glam::Vec2::new(source.z_min, source.z_max));
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
@ -277,14 +296,15 @@ impl DemRenderer {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("DemRendererCommandEncoder"),
});
self.camera.set_position(
get_animated_camera_position(
let camera_position = get_animated_camera_position(
self.animation_start.elapsed(),
self.get_max_dem_dimension(),
),
self.get_dem_centre(),
);
self.camera
.set_position(camera_position, self.get_dem_centre());
self.uniforms.set_camera_matrix(self.camera.get_matrix());
self.uniforms
.set_camera_position(camera_position.extend(1.0));
self.uniforms.update_buffer(queue);
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@ -378,11 +398,7 @@ fn create_vertices(dem: &Rc<Dem>) -> (Vec<Vertex>, Vec<u16>) {
(vertex_data.to_vec(), index_data.to_vec())
}
fn load_dem_texture(
source: &Dem,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> (wgpu::TextureView, glam::UVec2) {
fn load_dem_texture(source: &Dem, device: &wgpu::Device, queue: &wgpu::Queue) -> wgpu::TextureView {
let texture_size = wgpu::Extent3d {
width: source.num_cells_x,
height: source.num_cells_y,
@ -415,17 +431,14 @@ fn load_dem_texture(
texture_size,
);
(
texture.create_view(&wgpu::TextureViewDescriptor::default()),
glam::UVec2::new(source.num_cells_x, source.num_cells_y),
)
texture.create_view(&wgpu::TextureViewDescriptor::default())
}
fn create_dembvh_texture(
dem: &Dem,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> (wgpu::TextureView, glam::UVec2) {
) -> wgpu::TextureView {
let source = DemBvh::new(dem);
let dembvh_size = source.layers.first().expect("DEM BVH contains layers").size;
@ -466,10 +479,7 @@ fn create_dembvh_texture(
);
}
(
texture.create_view(&wgpu::TextureViewDescriptor::default()),
glam::UVec2::new(dembvh_size, dembvh_size),
)
texture.create_view(&wgpu::TextureViewDescriptor::default())
}
fn get_animated_camera_position(animation_time: std::time::Duration, dem_size: f32) -> glam::Vec3 {

View File

@ -1,12 +1,14 @@
struct VertexOutput {
@location(0) test: vec2<f32>,
@location(0) world_space_position: vec4<f32>,
@builtin(position) position: vec4<f32>,
};
struct Uniforms {
transform: mat4x4<f32>,
dem_texture_size: vec2<u32>,
dembvh_texture_size: vec2<u32>
camera_position: vec4<f32>,
dem_min_corner: vec2<f32>,
dem_cell_size: vec2<f32>,
dem_z_range: vec2<f32>
}
@group(0) @binding(0)
@ -18,6 +20,90 @@ var dem_texture: texture_2d<u32>;
@group(0) @binding(2)
var dembvh_texture: texture_2d<u32>;
struct BoundingNode {
index: vec2<u32>,
level: u32
}
struct AABB {
min_corner: vec3<f32>,
max_corner: vec3<f32>
}
struct Ray { origin: vec3<f32>, direction: vec3<f32> };
fn intersect_ray_with_aabb(ray: Ray, aabb: AABB) -> bool {
let t1 = (aabb.min_corner - ray.origin) / ray.direction;
let t2 = (aabb.max_corner - ray.origin) / ray.direction;
let t_mins = min(t1, t2);
let t_min = min(t_mins.x, min(t_mins.y, t_mins.z));
let t_maxs = max(t1, t2);
let t_max = max(t_maxs.x, max(t_maxs.y, t_maxs.z));
return t_min <= t_max;
}
fn scale_u16(value: u32, range: vec2<f32>) -> f32 {
return range.x + (f32(value - 1) / 65534.0) * (range.y - range.x);
}
fn get_xy_min_for_node(node: BoundingNode) -> vec2<f32> {
return uniforms.dem_min_corner.xy + uniforms.dem_cell_size * vec2<f32>(node.index) * exp2(f32(node.level));
}
fn get_xy_max_for_node(node: BoundingNode) -> vec2<f32> {
return uniforms.dem_min_corner.xy + uniforms.dem_cell_size * vec2<f32>(node.index + 1) * exp2(f32(node.level));
}
struct NodeStack {
stack: array<BoundingNode,64>,
count: u32
}
fn push_node_stack(stack: ptr<function,NodeStack>, node: BoundingNode) {
(*stack).stack[(*stack).count] = node;
(*stack).count++;
}
fn pop_node_stack(stack: ptr<function,NodeStack>) -> BoundingNode {
(*stack).count--;
return (*stack).stack[(*stack).count];
}
fn intersect_ray_with_node(ray: Ray, root_node: BoundingNode) -> bool {
var node_stack: NodeStack;
node_stack.count = 0u;
push_node_stack(&node_stack, root_node);
while node_stack.count > 0 {
let node = pop_node_stack(&node_stack);
let minmax_z = textureLoad(dembvh_texture, node.index, i32(node.level)).rg;
if minmax_z.r == 0 {
return false;
}
let min_z = scale_u16(minmax_z.r, uniforms.dem_z_range);
let max_z = scale_u16(minmax_z.g, uniforms.dem_z_range);
var aabb: AABB ;
aabb.min_corner = vec3<f32>(get_xy_min_for_node(node), min_z);
aabb.max_corner = vec3<f32>(get_xy_max_for_node(node), min_z);
if intersect_ray_with_aabb(ray, aabb) {
if node.level == 0 {
return true;
} else {
let next_index = node.index * 2;
var next_node: BoundingNode;
next_node.index = next_index;
next_node.level = node.level - 1;
push_node_stack(&node_stack, next_node);
next_node.index = next_index + vec2<u32>(1, 0);
push_node_stack(&node_stack, next_node);
next_node.index = next_index + vec2<u32>(0, 1);
push_node_stack(&node_stack, next_node);
next_node.index = next_index + vec2<u32>(1, 1);
push_node_stack(&node_stack, next_node);
}
}
}
return false;
}
@vertex
fn vs_main(
@ -25,14 +111,23 @@ fn vs_main(
) -> VertexOutput {
var result: VertexOutput;
result.position = uniforms.transform * position;
result.test = position.xy;
result.world_space_position = position;
return result;
}
@fragment
fn fs_solid(vertex: VertexOutput) -> @location(0) vec4<f32> {
let texture_index = vec2<i32>(fract(abs(vertex.test)/500.0)*vec2<f32>(uniforms.dem_texture_size));
let v_i = vec3<u32>(textureLoad(dem_texture, texture_index, 0).r, textureLoad(dembvh_texture, texture_index, 0).rg);
let v = vec3<f32>(v_i) / 65535.0;
return vec4<f32>(v, 1.0);
var ray: Ray;
ray.origin = vertex.world_space_position.xyz;
ray.direction = normalize(vertex.world_space_position.xyz - uniforms.camera_position.xyz);
var root_node: BoundingNode;
root_node.index = vec2<u32>(0);
root_node.level = textureNumLevels(dembvh_texture) - 1;
if intersect_ray_with_node(ray, root_node) {
return vec4<f32>(1.0);
} else {
discard;
}
}