diff --git a/src/app/dem_renderer/dem_renderer.wgsl b/src/app/dem_renderer/dem_renderer.wgsl index fe1f759..c800575 100644 --- a/src/app/dem_renderer/dem_renderer.wgsl +++ b/src/app/dem_renderer/dem_renderer.wgsl @@ -4,7 +4,8 @@ struct VertexOutput { } struct Uniforms { - transform: mat4x4, + camera_to_world_matrix: mat4x4, + world_to_ndc_matrix: mat4x4, camera_position: vec4, dem_min_corner: vec2, dem_cell_size: vec2, @@ -27,7 +28,7 @@ fn vs_main( @location(0) position: vec4, ) -> VertexOutput { var result: VertexOutput; - result.position = uniforms.transform * position; + result.position = uniforms.world_to_ndc_matrix * position; result.world_space_position = position; return result; } @@ -50,8 +51,41 @@ fn fs_solid(vertex: VertexOutput) -> @location(0) vec4 { ray, root_node, &hit_index) { - let v_i = textureLoad(dem_texture, hit_index, 0).r; - return vec4(vec3(v_i) / 65535.0, 1.0); + //Calculate x-values of cell corners + let v00 = textureLoad(dem_texture, hit_index, 0).r; + let v01 = textureLoad(dem_texture, hit_index + vec2(0,1), 0).r; + let v10 = textureLoad(dem_texture, hit_index + vec2(1,0), 0).r; + let v11 = textureLoad(dem_texture, hit_index + vec2(1,1), 0).r; + let z00 = 12.0 * f32(v00) / 65535.0; + let z01 = 12.0 * f32(v01) / 65535.0; + let z10 = 12.0 * f32(v10) / 65535.0; + let z11 = 12.0 * f32(v11) / 65535.0; + // Calculate xyz of cell corners + let xy00 = uniforms.dem_min_corner.xy + + uniforms.dem_cell_size * vec2(hit_index); + let p00 = vec3(xy00, z00); + let p01 = vec3(xy00 + vec2(0, 1), z01); + let p10 = vec3(xy00 + vec2(1, 0), z10); + let p11 = vec3(xy00 + vec2(1, 1), z11); + // Intersect ray with the plane of each triangle and then take the + // point that's inside it's triangle. + // p is the point and p0, p1 and p2 are the triangle corners. + let p_t0 = intersect_ray_with_triangle_plane(ray, p00, p01, p11); + let p_t1 = intersect_ray_with_triangle_plane(ray, p00, p10, p11); + let point_is_in_first_triangle = point_is_in_triangle(p_t0, p00, p01, p11); + let p = select(p_t1, p_t0, point_is_in_first_triangle); + let p0 = p00; + let p1 = select(p10, p01, point_is_in_first_triangle); + let p2 = p11; + // Estimate normal as cross product of triangle for now + var normal = normalize(cross(p1-p0, p2-p0)); + normal *= sign(normal.z); //Ensure normal points up + // Calculate light + let sun_direction = (uniforms.camera_to_world_matrix + * vec4(normalize(vec3(1.0, 1.0, 1.0)), 0.0)).xyz; + let l = dot(normal, sun_direction); + return vec4(l, l, l, 1.0); + //return vec4(normal.xy, 0.0, 1.0); } else { discard; } diff --git a/src/app/dem_renderer/mod.rs b/src/app/dem_renderer/mod.rs index 12e1351..02cf8c9 100644 --- a/src/app/dem_renderer/mod.rs +++ b/src/app/dem_renderer/mod.rs @@ -62,15 +62,20 @@ impl Camera { glam::Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, ratio, 1.0, 10.0); } - fn get_matrix(&self) -> glam::Mat4 { + fn get_world_to_ndc_matrix(&self) -> glam::Mat4 { self.projection_matrix * self.view_matrix } + + fn get_camera_to_world_matrix(&self) -> glam::Mat4 { + self.view_matrix.inverse() + } } #[repr(C)] #[derive(Clone, Copy, Pod, Zeroable)] struct UniformBufferContents { - camera_matrix: [f32; 16], + camera_to_world_matrix: [f32; 16], + world_to_ndc_matrix: [f32; 16], camera_position: [f32; 4], dem_min_corner: [f32; 2], dem_cell_size: [f32; 2], @@ -80,7 +85,7 @@ struct UniformBufferContents { // member with the largest alignment. (The mat4x4 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; +const UNIFORM_BUFFER_SIZE: u64 = 176; struct UniformBufferManager { cpu_buffer: UniformBufferContents, @@ -101,10 +106,16 @@ impl UniformBufferManager { } } - fn set_camera_matrix(&mut self, camera_matrix: glam::Mat4) { + fn set_camera_to_world_matrix(&mut self, camera_to_world_matrix: glam::Mat4) { self.cpu_buffer - .camera_matrix - .clone_from_slice(&camera_matrix.to_cols_array()) + .camera_to_world_matrix + .clone_from_slice(&camera_to_world_matrix.to_cols_array()) + } + + fn set_world_to_ndc_matrix(&mut self, world_to_ndc_matrix: glam::Mat4) { + self.cpu_buffer + .world_to_ndc_matrix + .clone_from_slice(&world_to_ndc_matrix.to_cols_array()) } fn set_camera_position(&mut self, camera_position: glam::Vec4) { @@ -301,7 +312,8 @@ impl DemRenderer { ); self.camera .set_position(camera_position, self.get_dem_centre()); - self.uniforms.set_camera_matrix(self.camera.get_matrix()); + self.uniforms.set_camera_to_world_matrix(self.camera.get_camera_to_world_matrix()); + self.uniforms.set_world_to_ndc_matrix(self.camera.get_world_to_ndc_matrix()); self.uniforms .set_camera_position(camera_position.extend(1.0)); self.uniforms.update_buffer(queue); @@ -482,7 +494,7 @@ fn create_dembvh_texture( } fn get_animated_camera_position(animation_time: std::time::Duration, dem_size: f32) -> glam::Vec3 { - let animation_phase = 2.0 * std::f32::consts::PI * (animation_time.as_secs_f32() % 10.0) / 10.0; + let animation_phase = 2.0 * std::f32::consts::PI * (animation_time.as_secs_f32() % 25.0) / 25.0; glam::Vec3::new( dem_size * f32::sin(animation_phase), dem_size * f32::cos(animation_phase), diff --git a/src/app/dem_renderer/ray_intersection.wgsl b/src/app/dem_renderer/ray_intersection.wgsl index 86d845a..2dd4725 100644 --- a/src/app/dem_renderer/ray_intersection.wgsl +++ b/src/app/dem_renderer/ray_intersection.wgsl @@ -114,3 +114,26 @@ fn intersect_ray_with_node(tree_texture: texture_2d, } return closest_hit_distance < 1.0e+20; } + + +fn intersect_ray_with_triangle_plane(ray: Ray, + p0: vec3, + p1: vec3, + p2: vec3) -> vec3 { + let n = cross(p1-p0, p2-p0); + return ray.origin + ray.direction * dot(p0 - ray.origin, n) / dot(ray.direction, n); +} + + +fn point_is_inside_triangle_side(p: vec3, + p0: vec3, p1: vec3, p2: vec3) -> bool { + return dot(cross(p2-p1, p-p1), cross(p2-p1, p0-p1)) >= 0; +} + + +fn point_is_in_triangle(p: vec3, + p0: vec3, p1: vec3, p2: vec3) -> bool { + return point_is_inside_triangle_side(p, p0, p1, p2) + && point_is_inside_triangle_side(p, p1, p2, p0) + && point_is_inside_triangle_side(p, p2, p0, p1); +}