From b7add49f4cd3dc63ef912a51cc4473e42360f1c7 Mon Sep 17 00:00:00 2001 From: davids91 Date: Sun, 21 Jul 2024 17:25:23 +0200 Subject: [PATCH] Bugfixes, API extensions, Debug data and logic --- examples/wgpu_render.rs | 223 ++++++++++++++++++--- src/octree/raytracing/wgpu/data.rs | 4 +- src/octree/raytracing/wgpu/mod.rs | 18 +- src/octree/raytracing/wgpu/raytracing.wgsl | 59 ++++-- src/octree/raytracing/wgpu/types.rs | 24 +++ 5 files changed, 276 insertions(+), 52 deletions(-) diff --git a/examples/wgpu_render.rs b/examples/wgpu_render.rs index 2e03463..2bf6dae 100644 --- a/examples/wgpu_render.rs +++ b/examples/wgpu_render.rs @@ -7,9 +7,12 @@ use shocovox_rs::octree::V3cf32; use shocovox_rs::octree::VoxelData; use std::sync::Arc; use winit::application::ApplicationHandler; +use winit::event::ElementState; +use winit::event::MouseButton; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::event_loop::{ControlFlow, EventLoop}; +use winit::keyboard::NamedKey; use winit::window::Window; use winit::window::WindowId; @@ -17,7 +20,10 @@ use winit::window::WindowId; const DISPLAY_RESOLUTION: [u32; 2] = [1024, 768]; #[cfg(feature = "wgpu")] -const ARRAY_DIMENSION: u32 = 64; +const OCTREE_SIZE: u32 = 128; + +#[cfg(feature = "wgpu")] +const BRICK_DIMENSION: usize = 32; #[cfg(feature = "wgpu")] struct SvxRenderExample @@ -27,6 +33,10 @@ where backend: SvxRenderBackend, window: Option>, tree: Arc>, + + // User input variables + last_cursor_pos: winit::dpi::PhysicalPosition, + left_mouse_btn_pressed: bool, } #[cfg(feature = "wgpu")] @@ -70,6 +80,31 @@ where Some(&self.tree), )); } + WindowEvent::MouseInput { + device_id: _, + state, + button, + } => { + if button == MouseButton::Left && state.is_pressed() { + self.left_mouse_btn_pressed = true; + } else if button == MouseButton::Left && !state.is_pressed() { + self.left_mouse_btn_pressed = false; + } + } + WindowEvent::CursorMoved { + device_id: _, + position, + } => { + let delta_x = ((position.x - self.last_cursor_pos.x) as f32) + .min(100.) + .max(-100.); + if self.left_mouse_btn_pressed { + self.backend.update_viewport_glass_fov( + self.backend.viewport().w_h_fov.z * (1. + delta_x / 100.), + ); + } + self.last_cursor_pos = position; + } WindowEvent::KeyboardInput { device_id: _, event, @@ -77,19 +112,27 @@ where } => { if let winit::keyboard::Key::Named(named) = event.logical_key { match named { - winit::keyboard::NamedKey::ArrowUp => { - self.backend.update_viewport_origin(V3cf32::new(0., 1., 0.)); + NamedKey::ArrowUp => { + self.backend.update_viewport_origin(V3cf32::new(0., 5., 0.)); } - winit::keyboard::NamedKey::ArrowDown => { + NamedKey::ArrowDown => { self.backend - .update_viewport_origin(V3cf32::new(0., -1., 0.)); + .update_viewport_origin(V3cf32::new(0., -5., 0.)); } - winit::keyboard::NamedKey::ArrowLeft => { + NamedKey::ArrowLeft => { self.backend - .update_viewport_origin(V3cf32::new(-1., 0., 0.)); + .update_viewport_origin(V3cf32::new(-5., 0., 0.)); + } + NamedKey::ArrowRight => { + self.backend.update_viewport_origin(V3cf32::new(5., 0., 0.)); } - winit::keyboard::NamedKey::ArrowRight => { - self.backend.update_viewport_origin(V3cf32::new(1., 0., 0.)); + NamedKey::PageUp => { + self.backend + .update_viewport_origin(self.backend.viewport().direction * 5.); + } + NamedKey::PageDown => { + self.backend + .update_viewport_origin(self.backend.viewport().direction * -5.); } _ => {} } @@ -103,42 +146,149 @@ where #[cfg(feature = "wgpu")] fn main() { // fill octree with data - let mut tree = shocovox_rs::octree::Octree::::new(ARRAY_DIMENSION) + let mut tree = shocovox_rs::octree::Octree::::new(OCTREE_SIZE) .ok() .unwrap(); + // single color voxel + // tree.insert_at_lod( + // &V3c::new(0, 0, 0), + // 4, + // Albedo::default() + // .with_red(1.) + // .with_green(0.) + // .with_blue(1.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // Different color voxels + // tree.insert( + // &V3c::new(0, 0, 0), + // Albedo::default() + // .with_red(0.) + // .with_green(0.) + // .with_blue(0.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(0, 0, 1), + // Albedo::default() + // .with_red(0.) + // .with_green(0.) + // .with_blue(1.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(0, 1, 0), + // Albedo::default() + // .with_red(0.) + // .with_green(1.) + // .with_blue(0.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(0, 1, 1), + // Albedo::default() + // .with_red(0.) + // .with_green(1.) + // .with_blue(1.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(1, 0, 0), + // Albedo::default() + // .with_red(1.) + // .with_green(0.) + // .with_blue(0.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(1, 0, 1), + // Albedo::default() + // .with_red(1.) + // .with_green(0.) + // .with_blue(1.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(1, 1, 0), + // Albedo::default() + // .with_red(1.) + // .with_green(1.) + // .with_blue(0.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // tree.insert( + // &V3c::new(1, 1, 1), + // Albedo::default() + // .with_red(1.) + // .with_green(1.) + // .with_blue(1.) + // .with_alpha(1.), + // ) + // .ok() + // .unwrap(); + + // assert!( + // Albedo::default() + // .with_red(1.) + // .with_green(0.) + // .with_blue(0.) + // .with_alpha(1.) + // == *tree.get(&V3c::new(1, 0, 0)).unwrap() + // ); + tree.insert(&V3c::new(1, 3, 3), Albedo::from(0x66FFFF)) .ok() .unwrap(); - for x in 0..ARRAY_DIMENSION { - for y in 0..ARRAY_DIMENSION { - for z in 0..ARRAY_DIMENSION { - if ((x < (ARRAY_DIMENSION / 4) - || y < (ARRAY_DIMENSION / 4) - || z < (ARRAY_DIMENSION / 4)) + for x in 0..OCTREE_SIZE { + for y in 0..OCTREE_SIZE { + for z in 0..OCTREE_SIZE { + if ((x < (OCTREE_SIZE / 4) || y < (OCTREE_SIZE / 4) || z < (OCTREE_SIZE / 4)) && (0 == x % 2 && 0 == y % 4 && 0 == z % 2)) - || ((ARRAY_DIMENSION / 2) <= x - && (ARRAY_DIMENSION / 2) <= y - && (ARRAY_DIMENSION / 2) <= z) + || ((OCTREE_SIZE / 2) <= x && (OCTREE_SIZE / 2) <= y && (OCTREE_SIZE / 2) <= z) { - let r = if 0 == x % (ARRAY_DIMENSION / 4) { - (x as f32 / ARRAY_DIMENSION as f32 * 255.) as u32 + let r = if 0 == x % (OCTREE_SIZE / 4) { + x as f32 / OCTREE_SIZE as f32 } else { - 128 + 0.5 }; - let g = if 0 == y % (ARRAY_DIMENSION / 4) { - (y as f32 / ARRAY_DIMENSION as f32 * 255.) as u32 + let g = if 0 == y % (OCTREE_SIZE / 4) { + y as f32 / OCTREE_SIZE as f32 } else { - 128 + 0.5 }; - let b = if 0 == z % (ARRAY_DIMENSION / 4) { - (z as f32 / ARRAY_DIMENSION as f32 * 255.) as u32 + let b = if 0 == z % (OCTREE_SIZE / 4) { + z as f32 / OCTREE_SIZE as f32 } else { - 128 + 0.5 }; tree.insert( &V3c::new(x, y, z), - Albedo::from(r | (g << 8) | (b << 16) | 0xFF000000), + Albedo::default().with_red(r).with_green(g).with_blue(b), ) .ok() .unwrap(); @@ -150,9 +300,9 @@ fn main() { // Fire up the display let origin = V3c::new( - ARRAY_DIMENSION as f32 * 2., - ARRAY_DIMENSION as f32 / 2., - ARRAY_DIMENSION as f32 * -2., + OCTREE_SIZE as f32 * 2., + OCTREE_SIZE as f32 / 2., + OCTREE_SIZE as f32 * -2., ); let event_loop = EventLoop::new().unwrap(); @@ -161,13 +311,20 @@ fn main() { .with_viewport(Viewport { direction: (V3c::new(0., 0., 0.) - origin).normalized(), origin, - w_h_fov: V3c::new(10., 10., 10.), + w_h_fov: V3c::new(10., 10., 3.5), }); + // .with_viewport(Viewport { + // direction: V3c::new(1., 0., 0.), + // origin: V3c::new(0., 1., 0.), + // w_h_fov: V3c::new(0., 0., 1.), + // }); let mut example = SvxRenderExample { backend, window: None, tree: showcase.clone(), + last_cursor_pos: Default::default(), + left_mouse_btn_pressed: false, }; env_logger::init(); diff --git a/src/octree/raytracing/wgpu/data.rs b/src/octree/raytracing/wgpu/data.rs index 244d341..bd5bab6 100644 --- a/src/octree/raytracing/wgpu/data.rs +++ b/src/octree/raytracing/wgpu/data.rs @@ -1,4 +1,4 @@ -use encase::StorageBuffer; +use encase::{ShaderSize, StorageBuffer}; use crate::octree::{ empty_marker, raytracing::wgpu::types::Voxelement, types::NodeChildrenArray, NodeContent, @@ -167,7 +167,7 @@ where // Upload data to buffers let octree_meta = OctreeMetaData::from(self); - let mut buffer = StorageBuffer::new(Vec::::new()); + let mut buffer = encase::UniformBuffer::new(Vec::::new()); buffer.write(&octree_meta).unwrap(); if let Some(metadata_buffer) = &app.metadata_buffer { app.queue diff --git a/src/octree/raytracing/wgpu/mod.rs b/src/octree/raytracing/wgpu/mod.rs index 43cdd24..c2d1594 100644 --- a/src/octree/raytracing/wgpu/mod.rs +++ b/src/octree/raytracing/wgpu/mod.rs @@ -127,7 +127,23 @@ impl<'a> SvxRenderBackend { ) } - pub fn update_viewport_direction(&mut self, direction: V3cf32) { + pub fn update_viewport_direction(&mut self, delta: V3cf32) { + self.viewport.direction = (self.viewport.direction + delta).normalized(); + let mut buffer = UniformBuffer::new(Vec::::new()); + buffer.write(&self.viewport).unwrap(); + self.queue + .as_ref() + .expect("Expected SvxRenderApp to have a vaild rendering queue!") + .write_buffer( + self.viewport_buffer + .as_ref() + .expect("Expected SvxRenderApp to have a vaild Viewport buffer!"), + 0, + &buffer.into_inner(), + ) + } + + pub fn set_viewport_direction(&mut self, direction: V3cf32) { self.viewport.direction = direction; let mut buffer = UniformBuffer::new(Vec::::new()); buffer.write(&self.viewport).unwrap(); diff --git a/src/octree/raytracing/wgpu/raytracing.wgsl b/src/octree/raytracing/wgpu/raytracing.wgsl index 93e15d2..dd2f75f 100644 --- a/src/octree/raytracing/wgpu/raytracing.wgsl +++ b/src/octree/raytracing/wgpu/raytracing.wgsl @@ -463,7 +463,11 @@ fn get_by_ray(ray_: Line) -> OctreeRayIntersection{ ); node_stack_i = 1; } - while(0 < node_stack_i && node_stack_i < max_depth) { + // +++ DEBUG +++ + var i = 0.; + // --- DEBUG --- + while(0 < node_stack_i && node_stack_i < max_depth && i < 15.) { + i = i + 1.; var current_bounds = node_stack[node_stack_i - 1].bounds; var current_node = nodes[node_stack[node_stack_i - 1].node]; //!NOTE: should be const, but then it can not be indexed dynamically var target_octant = node_stack[node_stack_i - 1].target_octant; @@ -486,7 +490,22 @@ fn get_by_ray(ray_: Line) -> OctreeRayIntersection{ current_bounds.min_position = current_bounds.min_position + vec3f(leaf_brick_hit.index) * current_bounds.size; result.hit = true; - result.albedo = voxels[hit_in_voxels].albedo; + result.albedo.r = voxels[hit_in_voxels].r; + result.albedo.g = voxels[hit_in_voxels].g; + result.albedo.b = voxels[hit_in_voxels].b; + result.albedo.a = voxels[hit_in_voxels].a; + + // +++ DEBUG +++ + if(i <= 15.){ + result.albedo.r = i / 15.; + }else{ + result.albedo.r = 0.; + result.albedo.g = 0.; + result.albedo.b = 0.; + } + // --- DEBUG --- + + result.content = voxels[hit_in_voxels].content; result.collision_point = point_in_ray_at_distance(ray, ray_current_distance); result.impact_normal = cube_impact_normal(current_bounds, result.collision_point); @@ -589,16 +608,17 @@ fn get_by_ray(ray_: Line) -> OctreeRayIntersection{ } struct Voxelement { - albedo : vec4f, + // albedo : vec4f, + r: f32, + g: f32, + b: f32, + a: f32, content: u32, } fn is_empty(e: Voxelement) -> bool { return ( - 0. == e.albedo.r - && 0. == e.albedo.g - && 0. == e.albedo.b - && 0. == e.albedo.a + 0. == e.r && 0. == e.g && 0. == e.b && 0. == e.a && 0 == e.content ); } @@ -652,10 +672,14 @@ fn update( @builtin(global_invocation_id) invocation_id: vec3, @builtin(num_workgroups) num_workgroups: vec3, ) { - let pixel_location = vec2u(invocation_id.xy); + let screen_size = num_workgroups * 8; + let pixel_location = vec2u( + invocation_id.x, + screen_size.y - invocation_id.y, + ); let pixel_location_normalized = vec2f( - f32(invocation_id.x) / f32(num_workgroups.x * 8), - f32(invocation_id.y) / f32(num_workgroups.y * 8) + f32(invocation_id.x) / f32(screen_size.x), + f32(invocation_id.y) / f32(screen_size.y) ); let viewport_up_direction = vec3f(0., 1., 0.); let viewport_right_direction = normalize(cross( @@ -672,26 +696,29 @@ fn update( ; var ray = Line(ray_endpoint, normalize(ray_endpoint - viewport.origin)); - // +++ DEBUG +++ var rgb_result = vec3f(0.5,0.5,0.5); var ray_result = get_by_ray(ray); if ray_result.hit == true { let diffuse_light_strength = ( dot(ray_result.impact_normal, vec3f(-0.5,0.5,-0.5)) / 2. + 0.5 ); - let result_with_lights = ray_result.albedo.rgb * diffuse_light_strength; + let result_with_lights = vec3f( + ray_result.albedo.r, ray_result.albedo.g, ray_result.albedo.b + ) * diffuse_light_strength; rgb_result = result_with_lights.rgb; } - /*// root bounds hit ray - var root_bounds = Cube(vec3(0.,0.,0.), f32(octreeMetaData.octree_size)); + // +++ DEBUG +++ + // root bounds hit ray +/* var root_bounds = Cube(vec3(0.,0.,0.), f32(octreeMetaData.octree_size)); if cube_intersect_ray(root_bounds, ray).hit == true { rgb_result.b = 1.; } rgb_result.r = pixel_location_normalized.x; - rgb_result.g = pixel_location_normalized.y; -*/ // --- DEBUG --- + rgb_result.g = pixel_location_normalized.y; */ + + // --- DEBUG --- textureStore(output_texture, pixel_location, vec4f(rgb_result, 1.)); } diff --git a/src/octree/raytracing/wgpu/types.rs b/src/octree/raytracing/wgpu/types.rs index 62520ef..3acb5af 100644 --- a/src/octree/raytracing/wgpu/types.rs +++ b/src/octree/raytracing/wgpu/types.rs @@ -70,6 +70,30 @@ impl Default for Viewport { } } +impl Viewport { + pub fn new_with_delta_origin(&self, delta: V3cf32) -> Viewport { + Viewport { + origin: self.origin + delta, + direction: self.direction, + w_h_fov: self.w_h_fov, + } + } + pub fn new_with_delta_direction(&self, delta: V3cf32) -> Viewport { + Viewport { + origin: self.origin, + direction: self.direction + delta, + w_h_fov: self.w_h_fov, + } + } + pub fn new_with_delta_w_h_fov(&self, delta: V3cf32) -> Viewport { + Viewport { + origin: self.origin, + direction: self.direction, + w_h_fov: self.w_h_fov + delta, + } + } +} + pub struct SvxRenderBackend { //render data and parameters pub(crate) viewport: Viewport,