diff --git a/src/client/handle_input.rs b/src/client/handle_input.rs index 34cb7c6..3e68c43 100644 --- a/src/client/handle_input.rs +++ b/src/client/handle_input.rs @@ -1,11 +1,7 @@ -use std::{f32::consts::PI, time::Duration}; +use std::time::Duration; use nalgebra::Rotation3; -use winit::{ - dpi::{LogicalPosition, PhysicalPosition}, - keyboard::KeyCode as Key, - window::CursorGrabMode, -}; +use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode}; use super::Client; @@ -27,11 +23,13 @@ impl Client<'_> { self.keep_cursor = true; window.set_cursor_grab(CursorGrabMode::Confined) }) - .expect("wah"); + .expect("cursor lock"); } else { self.keep_cursor = false; window.set_cursor_visible(true); - window.set_cursor_grab(CursorGrabMode::None).expect("wah"); + window + .set_cursor_grab(CursorGrabMode::None) + .expect("cursor unlock"); }; } return; @@ -42,21 +40,18 @@ impl Client<'_> { let size = window.inner_size(); window .set_cursor_position(PhysicalPosition::new(size.width / 2, size.height / 2)) - .expect("wah"); + .expect("cursor move"); } } - let delta = input.mouse_delta; + let delta = input.mouse_delta * 0.003; if delta.x != 0.0 { - state.camera.orientation = Rotation3::from_axis_angle( - &state.camera.up(), - (delta.x * 0.003).clamp(-PI, PI), - ) * state.camera.orientation; + state.camera.orientation = Rotation3::from_axis_angle(&state.camera.up(), delta.x) + * state.camera.orientation; } if delta.y != 0.0 { - state.camera.orientation = Rotation3::from_axis_angle( - &state.camera.right(), - (delta.y * 0.003).clamp(-PI, PI), - ) * state.camera.orientation; + state.camera.orientation = + Rotation3::from_axis_angle(&state.camera.right(), delta.y) + * state.camera.orientation; } } let rot_dist = 1.0 * dt; @@ -95,13 +90,5 @@ impl Client<'_> { if input.pressed(Key::ShiftLeft) { state.camera.pos += *state.camera.down() * move_dist; } - if input.pressed(Key::KeyZ) { - state.camera_scroll += dt * 10.0; - state.camera.scale = (state.camera_scroll * 0.1).exp(); - } - if input.pressed(Key::KeyX) { - state.camera_scroll -= dt * 10.0; - state.camera.scale = (state.camera_scroll * 0.1).exp(); - } } } diff --git a/src/client/render/voxel/group.rs b/src/client/render/voxel/group.rs index c4a5b41..92bf26d 100644 --- a/src/client/render/voxel/group.rs +++ b/src/client/render/voxel/group.rs @@ -5,6 +5,7 @@ use nalgebra::{Transform3, Vector3}; pub struct VoxelGroup { pub transform: Transform3, pub dimensions: Vector3, + pub offset: u32, } unsafe impl bytemuck::Pod for VoxelGroup {} diff --git a/src/client/render/voxel/pipeline.rs b/src/client/render/voxel/pipeline.rs index 23e234e..8b978b4 100644 --- a/src/client/render/voxel/pipeline.rs +++ b/src/client/render/voxel/pipeline.rs @@ -155,6 +155,7 @@ impl VoxelPipeline { let group = VoxelGroup { transform: Transform3::identity() * thing.inverse(), dimensions: Vector3::new(lx as u32, ly as u32, lz as u32), + offset: 0, }; self.voxel_groups.update( device, diff --git a/src/client/render/voxel/shader.wgsl b/src/client/render/voxel/shader.wgsl index 9dccfa0..3adb6e3 100644 --- a/src/client/render/voxel/shader.wgsl +++ b/src/client/render/voxel/shader.wgsl @@ -16,6 +16,7 @@ struct View { struct VoxelGroup { transform: mat4x4, dimensions: vec3, + offset: u32, }; @group(0) @binding(0) @@ -43,106 +44,82 @@ fn vs_main( // Fragment shader -const n0 = vec3(1.0, 0.0, 0.0); -const n1 = -n0; -const n2 = vec3(0.0, 1.0, 0.0); -const n3 = -n2; -const n4 = vec3(0.0, 0.0, 1.0); -const n5 = -n4; +const X_AXIS = vec3(1.0, 0.0, 0.0); +const Y_AXIS = vec3(0.0, 1.0, 0.0); +const Z_AXIS = vec3(0.0, 0.0, 1.0); +const AXIS = mat3x3(X_AXIS, Y_AXIS, Z_AXIS); -const ORIGIN = vec3(0.0, 0.0, 0.0); -const ORIGIN2 = vec2(0.0, 0.0); -const NO_COLOR = vec4(0.0, 0.0, 0.0, 0.0); +const ZERO3F = vec3(0.0); +const ZERO2F = vec2(0.0); +const NO_COLOR = vec4(0.0); @fragment fn fs_main( in: VertexOutput, ) -> @location(0) vec4 { - let aspect = f32(view.height) / f32(view.width); - var pos = vec3(in.clip_position.x / f32(view.width), 1.0 - in.clip_position.y / f32(view.height), 1.0); - pos.x -= 0.5; - pos.y -= 0.5; - pos.x *= 2.0; - pos.y *= 2.0; - pos.y *= aspect; + // get position of the pixel; eye at origin, pixel on plane z = 1 + let win_dim = vec2(f32(view.width), f32(view.height)); + let aspect = win_dim.y / win_dim.x; + let pixel_pos = vec3( + (in.clip_position.xy / win_dim - vec2(0.5)) * vec2(2.0, -2.0 * aspect), + 1.0 + ); let group = voxel_groups[0]; let dim_f = vec3(group.dimensions); + let dim_i = vec3(group.dimensions); - // this should definitely be done per pixel trust me guys + // transform position so that group is at 0,0 & find direction let transform = group.transform * view.transform; - pos = (transform * vec4(pos, 1.0)).xyz; - let origin = (transform * vec4(ORIGIN, 1.0)).xyz; - let dir = normalize(pos - origin); + let dir = (transform * vec4(normalize(pixel_pos), 0.0)).xyz; + var pos = (transform * vec4(pixel_pos, 1.0)).xyz; - var p = ORIGIN; + // find where ray intersects with group + let plane_point = (vec3(1.0) - sign(dir)) / 2.0 * dim_f; + if outside3f(pos, ZERO3F, dim_f) { + // x = td + p, solve for t + let t = (plane_point - pos) / dir; + // points of intersection + let px = pos + t.x * dir; + let py = pos + t.y * dir; + let pz = pos + t.z * dir; - var na: vec3; - var nb: vec3; - var nc: vec3; - if dot(dir, n0) < 0.0 { - na = n0; - p.x = 1.0; - } else { - na = n1; - } - if dot(dir, n2) < 0.0 { - nb = n2; - p.y = 1.0; - } else { - nb = n3; - } - if dot(dir, n4) < 0.0 { - nc = n4; - p.z = 1.0; - } else { - nc = n5; - } - p *= dim_f; - - var vox_pos: vec3; - var offset = ORIGIN; - let dir_if = sign(dir) * ceil(abs(dir)); - if outside(pos, ORIGIN, dim_f) { - let ta = intersect(pos, dir, p, na); - let tb = intersect(pos, dir, p, nb); - let tc = intersect(pos, dir, p, nc); - let pa = pos + ta * dir; - let pb = pos + tb * dir; - let pc = pos + tc * dir; - - if inside2(pa.yz, ORIGIN2, dim_f.yz) && ta > 0.0 { - pos = pa; - } else if inside2(pb.xz, ORIGIN2, dim_f.xz) && tb > 0.0 { - pos = pb; - } else if inside2(pc.xy, ORIGIN2, dim_f.xy) && tc > 0.0 { - pos = pc; - } else { + // check if point is in bounds + let hit = vec3( + inside2f(px.yz, ZERO2F, dim_f.yz), + inside2f(py.xz, ZERO2F, dim_f.xz), + inside2f(pz.xy, ZERO2F, dim_f.xy), + ) && (t > ZERO3F); + if !any(hit) { return NO_COLOR; } + pos = select(select(pz, py, hit.y), px, hit.x); } - vox_pos = vec3(pos); - let dim_i = vec3(group.dimensions); - vox_pos = clamp(vox_pos, vec3(0, 0, 0), dim_i - vec3(1, 1, 1)); + var vox_pos = clamp(vec3(pos), vec3(0), dim_i - vec3(1)); + let dir_if = sign(dir) * ceil(abs(dir)); let dir_i = vec3(dir_if); + // time to move 1 unit using dir let inc_t = abs(1.0 / dir); let corner = vec3(vox_pos) + vec3(0.5, 0.5, 0.5) + dir_if / 2.0; + + // time of next plane hit for each direction var next_t = inc_t * abs(pos - corner); var color = NO_COLOR; - var t = 0; + var safety = 0; loop { - let i = u32(vox_pos.x + vox_pos.y * dim_i.x + vox_pos.z * dim_i.x * dim_i.y); + let i = u32(vox_pos.x + vox_pos.y * dim_i.x + vox_pos.z * dim_i.x * dim_i.y) + group.offset; let vcolor = unpack4x8unorm(voxels[i]); color += vec4(vcolor.xyz * vcolor.a * (1.0 - color.a), (1.0 - color.a) * vcolor.a); if color.a >= 1.0 { return color; } + // select next voxel to move to next based on least time if next_t.x < next_t.y && next_t.x < next_t.z { vox_pos.x += dir_i.x; next_t.x += inc_t.x; @@ -163,34 +140,18 @@ fn fs_main( } } - t += 1; - if t > 1000 { + safety += 1; + if safety > 1000 { break; } } return vec4(1.0, 0.0, 0.0, 1.0); } -fn intersect(lp: vec3, ld: vec3, pp: vec3, pn: vec3) -> f32 { - let v = pn * (lp - pp); - let a = v.x + v.y + v.z; - let u = pn * ld; - let b = u.x + u.y + u.z; - return -a / b; +fn outside3f(v: vec3, low: vec3, high: vec3) -> bool { + return any(v < low) || any(v > high); } -fn outside(v: vec3, low: vec3, high: vec3) -> bool { - return v.x < low.x || v.y < low.y || v.z < low.z || v.x > high.x || v.y > high.y || v.z > high.z; -} - -fn inside(v: vec3, low: vec3, high: vec3) -> bool { - return !outside(v, low, high); -} - -fn outside2(v: vec2, low: vec2, high: vec2) -> bool { - return v.x < low.x || v.y < low.y || v.x > high.x || v.y > high.y; -} - -fn inside2(v: vec2, low: vec2, high: vec2) -> bool { - return !outside2(v, low, high); +fn inside2f(v: vec2, low: vec2, high: vec2) -> bool { + return all(v >= low) && all(v <= high); }