From d5ed196e2e250ac74eea855f3cecb0520af7b7d0 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Wed, 18 Sep 2024 17:19:57 -0400 Subject: [PATCH] octree node deduplication --- Cargo.lock | 17 +- Cargo.toml | 1 + src/client/handle_input.rs | 24 +- src/client/mod.rs | 2 - src/client/render/voxel/ray_oct/mod.rs | 4 +- .../render/voxel/ray_oct/shader/compute.wgsl | 227 ++++-------------- ...mpute_working.wgsl => compute_shadow.wgsl} | 225 ++++++++++++++--- src/common/component/chunk/mod.rs | 2 +- src/util/oct_tree.rs | 106 +++----- 9 files changed, 283 insertions(+), 325 deletions(-) rename src/client/render/voxel/ray_oct/shader/{compute_working.wgsl => compute_shadow.wgsl} (51%) diff --git a/Cargo.lock b/Cargo.lock index 3c6b5e5..56d400e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ dependencies = [ "bevy_utils", "downcast-rs", "fixedbitset", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "thiserror", "thread_local", @@ -203,7 +203,7 @@ checksum = "eb270c98a96243b29465139ed10bda2f675d00a11904f6588a5f7fc4774119c7" dependencies = [ "proc-macro2", "quote", - "rustc-hash", + "rustc-hash 1.1.0", "syn 2.0.77", "toml_edit 0.21.1", ] @@ -1065,7 +1065,7 @@ dependencies = [ "hexf-parse", "indexmap", "log", - "rustc-hash", + "rustc-hash 1.1.0", "spirv", "termcolor", "thiserror", @@ -1745,6 +1745,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustix" version = "0.38.37" @@ -2157,6 +2163,7 @@ dependencies = [ "ndarray", "pollster", "rand", + "rustc-hash 2.0.0", "simba 0.8.1", "simdnoise", "wgpu", @@ -2428,7 +2435,7 @@ dependencies = [ "parking_lot", "profiling", "raw-window-handle", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "wgpu-hal", @@ -2471,7 +2478,7 @@ dependencies = [ "range-alloc", "raw-window-handle", "renderdoc-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 05fb00e..b02335d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ bevy_ecs = "0.13.2" bevy_derive = "0.13.2" winit = {version="0.30.1", features=["serde"]} block-mesh = "0.2.0" +rustc-hash = "2.0.0" diff --git a/src/client/handle_input.rs b/src/client/handle_input.rs index 822229c..a1cce3a 100644 --- a/src/client/handle_input.rs +++ b/src/client/handle_input.rs @@ -2,12 +2,9 @@ use std::time::Duration; use nalgebra::Rotation3; use ndarray::Array3; -use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode}; +use winit::{keyboard::KeyCode as Key, window::CursorGrabMode}; -use crate::{ - common::ServerMessage, - common::component::{VoxelGrid, VoxelGridBundle}, -}; +use crate::common::{component::{chunk, VoxelGrid, VoxelGridBundle}, ServerMessage}; use super::{render::voxel::VoxelColor, Client}; @@ -28,16 +25,9 @@ impl Client<'_> { window.set_cursor_visible(false); window .set_cursor_grab(CursorGrabMode::Locked) - .map(|_| { - self.keep_cursor = false; - }) - .or_else(|_| { - self.keep_cursor = true; - window.set_cursor_grab(CursorGrabMode::Confined) - }) + .or_else(|_| window.set_cursor_grab(CursorGrabMode::Confined)) .expect("cursor lock"); } else { - self.keep_cursor = false; window.set_cursor_visible(true); window .set_cursor_grab(CursorGrabMode::None) @@ -45,12 +35,6 @@ impl Client<'_> { }; return; } - if self.keep_cursor { - let size = window.inner_size(); - // window - // .set_cursor_position(PhysicalPosition::new(size.width / 2, size.height / 2)) - // .expect("cursor move"); - } // camera orientation let old_camera = state.camera; @@ -84,7 +68,7 @@ impl Client<'_> { } // camera position - let move_dist = 64.0 * dt; + let move_dist = dt * (chunk::SIDE_LENGTH / 16) as f32; if input.pressed(Key::KeyW) { state.camera.pos += *state.camera.forward() * move_dist; } diff --git a/src/client/mod.rs b/src/client/mod.rs index b669d6d..59434ea 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -41,7 +41,6 @@ pub struct Client<'a> { input: Input, prev_update: Instant, grabbed_cursor: bool, - keep_cursor: bool, world: World, server: ServerHandle, server_id_map: HashMap, @@ -83,7 +82,6 @@ impl Client<'_> { input: Input::new(), prev_update: Instant::now(), grabbed_cursor: false, - keep_cursor: false, systems: ClientSystems { render_add_grid: world.register_system(add_grid), render_update_transform: world.register_system(system::render::update_transform), diff --git a/src/client/render/voxel/ray_oct/mod.rs b/src/client/render/voxel/ray_oct/mod.rs index c80f6b4..1204fd0 100644 --- a/src/client/render/voxel/ray_oct/mod.rs +++ b/src/client/render/voxel/ray_oct/mod.rs @@ -34,7 +34,7 @@ pub struct VoxelPipeline { } const RENDER_SHADER: wgpu::ShaderModuleDescriptor<'_> = include_wgsl!("shader/render.wgsl"); -const COMPUTE_SHADER: wgpu::ShaderModuleDescriptor<'_> = include_wgsl!("shader/compute_working.wgsl"); +const COMPUTE_SHADER: wgpu::ShaderModuleDescriptor<'_> = include_wgsl!("shader/compute.wgsl"); impl VoxelPipeline { pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self { @@ -82,7 +82,7 @@ impl VoxelPipeline { pub fn update_shader(&mut self, device: &wgpu::Device) { let Ok(shader) = std::fs::read_to_string( - env!("CARGO_MANIFEST_DIR").to_owned() + "/src/client/render/voxel/ray_oct/shader/compute_working.wgsl", + env!("CARGO_MANIFEST_DIR").to_owned() + "/src/client/render/voxel/ray_oct/shader/compute.wgsl", ) else { println!("Failed to reload shader!"); return; diff --git a/src/client/render/voxel/ray_oct/shader/compute.wgsl b/src/client/render/voxel/ray_oct/shader/compute.wgsl index 4a60e9f..b42f5b5 100644 --- a/src/client/render/voxel/ray_oct/shader/compute.wgsl +++ b/src/client/render/voxel/ray_oct/shader/compute.wgsl @@ -62,7 +62,7 @@ const EPSILON = 0.00000000001; const MAX_ITERS = 2000; // NOTE: CANNOT GO HIGHER THAN 23 due to how floating point // numbers are stored and the bit manipulation used -const MAX_SCALE: u32 = 10; +const MAX_SCALE: u32 = 13; fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { let gi = 0; @@ -115,7 +115,7 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { } axis = select(select(2u, 1u, hit.y), 0u, hit.x); } - let t_mult = f32(1u << (MAX_SCALE - group.scale)); + let t_mult =f32(1u << (MAX_SCALE - group.scale)); t_min *= t_mult; // time to move 1 unit in each direction let full = f32(1u << MAX_SCALE); @@ -124,174 +124,18 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { var t = max(0.0, t_offset); let dir_i = vec3(dir_if); - let dir_u = vec3((dir_i + vec3(1)) / 2); + let dir_u = vec3(dir_uf); let dir_bits = vec_to_dir(dir_u); let inv_dir_bits = 7 - dir_bits; var node_start = 1u; var scale = MAX_SCALE - 1; var scale_exp2 = 0.5; - var skip = LEAF_BIT; var color = vec4(0.0); var parents = array(); - - var child = 0u; - var vox_pos = vec3(1.0); - let t_center = t_min + scale_exp2 * inc_t; - if t > t_center.x { vox_pos.x = 1.5; child |= 4u; } - if t > t_center.y { vox_pos.y = 1.5; child |= 2u; } - if t > t_center.z { vox_pos.z = 1.5; child |= 1u; } - let min_adj = t_min - inc_t; - - var iters = 0; - loop { - if iters == MAX_ITERS { - return vec4(1.0, 0.0, 1.0, 1.0); - } - iters += 1; - let t_corner = vox_pos * inc_t + min_adj; - let node = voxels[group.offset + node_start + (child ^ inv_dir_bits)]; - if node >= LEAF_BIT { - if node != skip && node != LEAF_BIT { - skip = node; - let normal = normals[axis]; - let sun_dir = global_lights[0].dir; - let new_pos = pos_view + dir_view * t / t_mult - vec4(normals[axis] * 0.001, 0.0); - - let light = trace_light(new_pos, vec4(-sun_dir, 0.0)); - let diffuse = max(dot(sun_dir, normal) + 0.1, 0.0); - let ambient = 0.2; - let specular = (exp(max( - -(dot(reflect(dir_view.xyz, normal), sun_dir) + 0.90) * 4.0, 0.0 - )) - 1.0) * light; - let lighting = max(diffuse * light.a, ambient); - - let vcolor = get_color(node & LEAF_MASK); - let new_rgb = min(vcolor.xyz * lighting + specular.xyz + light.xyz * vcolor.xyz, vec3(1.0)); - let new_a = min(vcolor.a + specular.a, 1.0); - let new_color = vec4(new_rgb, new_a); - color += vec4(new_color.xyz * new_color.a, new_color.a) * (1.0 - color.a); - if color.a > FULL_ALPHA { break; } - } - - // move to next time point and determine which axis to move along - let t_next = t_corner + scale_exp2 * inc_t; - t = min(min(t_next.x, t_next.y), t_next.z); - axis = select(select(0u, 1u, t == t_next.y), 2u, t == t_next.z); - let move_dir = 4u >> axis; - - // check if need to pop stack - if (child & move_dir) > 0 { - // calculate new scale; first differing bit after adding - let axis_pos = vox_pos[axis]; - // AWARE - let differing = bitcast(axis_pos) ^ bitcast(axis_pos + scale_exp2); - scale = (bitcast(f32(differing)) >> 23) - 127 - (23 - MAX_SCALE); - scale_exp2 = bitcast((scale + 127 - MAX_SCALE) << 23); - if scale >= MAX_SCALE { break; } - - // restore & recalculate parent - let parent_info = parents[scale]; - node_start = parent_info >> 3; - child = parent_info & 7; - let scale_vec = vec3(scale + 23 - MAX_SCALE); - // remove bits lower than current scale - vox_pos = bitcast>((bitcast>(vox_pos) >> scale_vec) << scale_vec); - } - // move to next child and voxel position - child += move_dir; - vox_pos[axis] += scale_exp2; - } else { - // push current node to stack - parents[scale] = (node_start << 3) + child; - scale -= 1u; - - // calculate child node vars - scale_exp2 *= 0.5; - child = 0u; - let t_center = t_corner + scale_exp2 * inc_t; - if t > t_center.x { vox_pos.x += scale_exp2; child |= 4u; } - if t > t_center.y { vox_pos.y += scale_exp2; child |= 2u; } - if t > t_center.z { vox_pos.z += scale_exp2; child |= 1u; } - node_start += 8 + node; - } - } - // return vec4(f32(iters) / f32(MAX_ITERS), 0.0, 0.0, 1.0); - return color; -} - -fn trace_light(pos_view: vec4, dir_view: vec4) -> vec4 { - let gi = 0; - let group = voxel_groups[gi]; - if group.scale == 0 { - return vec4(0.0); - } - let dimensions = vec3(1u << group.scale); - let dim_f = vec3(dimensions); - let dim_i = vec3(dimensions); - - // transform so that group is at 0,0 - let pos_start = (group.transform_inv * pos_view).xyz; - var dir = (group.transform_inv * dir_view).xyz; - if dir.x == 0 {dir.x = EPSILON;} - if dir.y == 0 {dir.y = EPSILON;} - if dir.z == 0 {dir.z = EPSILON;} - - let dir_if = sign(dir); - let dir_uf = max(dir_if, vec3(0.0)); - - - - // calculate normals - var normals = mat3x3( - (group.transform * vec4(dir_if.x, 0.0, 0.0, 0.0)).xyz, - (group.transform * vec4(0.0, dir_if.y, 0.0, 0.0)).xyz, - (group.transform * vec4(0.0, 0.0, dir_if.z, 0.0)).xyz, - ); - var axis = 0u; - - // find where ray intersects with group - let pos_min = (vec3(1.0) - dir_uf) * dim_f; - // time of intersection; x = td + p, solve for t - var t_min = (pos_min - pos_start) / dir; - if outside3f(pos_start, ZERO3F, dim_f) { - // points of intersection - let px = pos_start + t_min.x * dir; - let py = pos_start + t_min.y * dir; - let pz = pos_start + t_min.z * dir; - - // 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_min > ZERO3F); - if !any(hit) { - return vec4(0.0); - } - axis = select(select(2u, 1u, hit.y), 0u, hit.x); - } - let t_mult = f32(1u << (MAX_SCALE - group.scale)); - t_min *= t_mult; - // time to move 1 unit in each direction - let full = f32(1u << MAX_SCALE); - let inc_t = abs(1.0 / dir) * full; - let t_offset = max(max(t_min.x, t_min.y), t_min.z); - var t = max(0.0, t_offset); + var prev = LEAF_BIT; var old_t = t; - let dir_i = vec3(dir_if); - let dir_u = vec3((dir_i + vec3(1)) / 2); - let dir_bits = vec_to_dir(dir_u); - let inv_dir_bits = 7 - dir_bits; - - var node_start = 1u; - var scale = MAX_SCALE - 1; - var scale_exp2 = 0.5; - var mask = vec4(0.0); - var skip = LEAF_BIT; - var parents = array(); - var child = 0u; var vox_pos = vec3(1.0); let t_center = t_min + scale_exp2 * inc_t; @@ -299,7 +143,6 @@ fn trace_light(pos_view: vec4, dir_view: vec4) -> vec4 { if t > t_center.y { vox_pos.y = 1.5; child |= 2u; } if t > t_center.z { vox_pos.z = 1.5; child |= 1u; } let min_adj = t_min - inc_t; - var data = 0u; var iters = 0; loop { @@ -310,20 +153,27 @@ fn trace_light(pos_view: vec4, dir_view: vec4) -> vec4 { let t_corner = vox_pos * inc_t + min_adj; let node = voxels[group.offset + node_start + (child ^ inv_dir_bits)]; if node >= LEAF_BIT { - if node != skip && node != LEAF_BIT { - skip = node; - if data == 3 { + if node != prev { + if node != LEAF_BIT { let dist = (t - old_t) / t_mult; - let vcolor = vec4(vec3(0.0), min(dist / 12.0, 1.0)); - mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); + old_t = t; + let filt = min(dist / 64.0, 1.0); + if prev == LEAF_BIT + 3 { + color.a += filt * (1.0 - color.a); + if color.a > FULL_ALPHA { break; } + } + let pos = (vox_pos - 1.5) * (dir_if) + 0.5 - scale_exp2 * (1.0 - dir_uf); + // let pos = t / t_mult; + // if true {return vec4(pos, 1.0);} + let vcolor = get_color(node & LEAF_MASK, pos); + let diffuse = max(dot(global_lights[0].dir, normals[axis]) + 0.1, 0.0); + let ambient = 0.2; + let lighting = max(diffuse, ambient); + let new_color = min(vcolor.xyz * lighting, vec3(1.0)); + color += vec4(new_color.xyz * vcolor.a, vcolor.a) * (1.0 - color.a); + if color.a > FULL_ALPHA { break; } } - data = node & LEAF_MASK; - if data != 3 && data != 0 { - let vcolor = get_color(data); - mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); - } - old_t = t; - if mask.a > FULL_ALPHA { break; } + prev = node; } // move to next time point and determine which axis to move along @@ -365,17 +215,13 @@ fn trace_light(pos_view: vec4, dir_view: vec4) -> vec4 { if t > t_center.x { vox_pos.x += scale_exp2; child |= 4u; } if t > t_center.y { vox_pos.y += scale_exp2; child |= 2u; } if t > t_center.z { vox_pos.z += scale_exp2; child |= 1u; } - node_start += 8 + node; + node_start = node; } } - if data == 3 { - let dist = (t - old_t) / t_mult; - let vcolor = vec4(vec3(0.0), min(dist / 12.0, 1.0)); - mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); - } - mask.a = 1.0 - mask.a; - mask = vec4(mask.a * mask.xyz, mask.a); - return mask; + // let fog = min(t / t_mult / 1000.0, 1.0); + // return vec4(color.xyz * (1.0 - fog) + vec3(fog), color.a * (1.0 - fog) + fog); + // return vec4(f32(iters) / f32(MAX_ITERS), 0.0, 0.0, 1.0); + return color; } fn dir_to_vec(bits: u32) -> vec3 { @@ -386,19 +232,24 @@ fn vec_to_dir(vec: vec3) -> u32 { return vec.x * 4 + vec.y * 2 + vec.z * 1; } -fn get_color(id: u32) -> vec4 { +fn get_color(id: u32, pos: vec3) -> vec4 { + let random = random(pos); + let random2 = random(pos + vec3(0.0001)); switch id { case 0u: { return vec4(0.0); } case 1u: { - return vec4(0.5, 0.5, 0.5, 1.0); + let color = vec3(0.5, 0.5, 0.5 + random * 0.2) * (random2 * 0.4 + 0.8); + return vec4(color, 1.0); } case 2u: { - return vec4(0.5, 1.0, 0.5, 1.0); + let color = vec3(0.4 + random * 0.2, 0.9, 0.4 + random * 0.2) * (random2 * 0.2 + 0.9); + return vec4(color, 1.0); } case 3u: { - return vec4(0.5, 0.5, 1.0, 0.5); + let color = vec3(0.5, 0.5, 1.0) * (random2 * 0.2 + 0.8); + return vec4(color, 0.5); } default: { return vec4(1.0, 0.0, 0.0, 1.0); @@ -406,6 +257,10 @@ fn get_color(id: u32) -> vec4 { } } +fn random(pos: vec3) -> f32 { + return fract(sin(dot(pos,vec3(12.9898,78.233,25.1279)))*43758.5453123); +} + fn outside3f(v: vec3, low: vec3, high: vec3) -> bool { return any(v < low) || any(v > high); } diff --git a/src/client/render/voxel/ray_oct/shader/compute_working.wgsl b/src/client/render/voxel/ray_oct/shader/compute_shadow.wgsl similarity index 51% rename from src/client/render/voxel/ray_oct/shader/compute_working.wgsl rename to src/client/render/voxel/ray_oct/shader/compute_shadow.wgsl index 7e06d77..4a60e9f 100644 --- a/src/client/render/voxel/ray_oct/shader/compute_working.wgsl +++ b/src/client/render/voxel/ray_oct/shader/compute_shadow.wgsl @@ -115,7 +115,7 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { } axis = select(select(2u, 1u, hit.y), 0u, hit.x); } - let t_mult =f32(1u << (MAX_SCALE - group.scale)); + let t_mult = f32(1u << (MAX_SCALE - group.scale)); t_min *= t_mult; // time to move 1 unit in each direction let full = f32(1u << MAX_SCALE); @@ -124,17 +124,16 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { var t = max(0.0, t_offset); let dir_i = vec3(dir_if); - let dir_u = vec3(dir_uf); + let dir_u = vec3((dir_i + vec3(1)) / 2); let dir_bits = vec_to_dir(dir_u); let inv_dir_bits = 7 - dir_bits; var node_start = 1u; var scale = MAX_SCALE - 1; var scale_exp2 = 0.5; + var skip = LEAF_BIT; var color = vec4(0.0); var parents = array(); - var prev = LEAF_BIT; - var old_t = t; var child = 0u; var vox_pos = vec3(1.0); @@ -153,27 +152,26 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { let t_corner = vox_pos * inc_t + min_adj; let node = voxels[group.offset + node_start + (child ^ inv_dir_bits)]; if node >= LEAF_BIT { - if node != prev { - if node != LEAF_BIT { - let dist = (t - old_t) / t_mult; - old_t = t; - let filt = min(dist / 64.0, 1.0); - if prev == LEAF_BIT + 3 { - color.a += filt * (1.0 - color.a); - if color.a > FULL_ALPHA { break; } - } - let pos = (vox_pos - 1.5) * (dir_if) + 0.5 - scale_exp2 * (1.0 - dir_uf); - // let pos = t / t_mult; - // if true {return vec4(pos, 1.0);} - let vcolor = get_color(node & LEAF_MASK, pos); - let diffuse = max(dot(global_lights[0].dir, normals[axis]) + 0.1, 0.0); - let ambient = 0.2; - let lighting = max(diffuse, ambient); - let new_color = min(vcolor.xyz * lighting, vec3(1.0)); - color += vec4(new_color.xyz * vcolor.a, vcolor.a) * (1.0 - color.a); - if color.a > FULL_ALPHA { break; } - } - prev = node; + if node != skip && node != LEAF_BIT { + skip = node; + let normal = normals[axis]; + let sun_dir = global_lights[0].dir; + let new_pos = pos_view + dir_view * t / t_mult - vec4(normals[axis] * 0.001, 0.0); + + let light = trace_light(new_pos, vec4(-sun_dir, 0.0)); + let diffuse = max(dot(sun_dir, normal) + 0.1, 0.0); + let ambient = 0.2; + let specular = (exp(max( + -(dot(reflect(dir_view.xyz, normal), sun_dir) + 0.90) * 4.0, 0.0 + )) - 1.0) * light; + let lighting = max(diffuse * light.a, ambient); + + let vcolor = get_color(node & LEAF_MASK); + let new_rgb = min(vcolor.xyz * lighting + specular.xyz + light.xyz * vcolor.xyz, vec3(1.0)); + let new_a = min(vcolor.a + specular.a, 1.0); + let new_color = vec4(new_rgb, new_a); + color += vec4(new_color.xyz * new_color.a, new_color.a) * (1.0 - color.a); + if color.a > FULL_ALPHA { break; } } // move to next time point and determine which axis to move along @@ -218,12 +216,168 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { node_start += 8 + node; } } - // let fog = min(t / t_mult / 1000.0, 1.0); - // return vec4(color.xyz * (1.0 - fog) + vec3(fog), color.a * (1.0 - fog) + fog); // return vec4(f32(iters) / f32(MAX_ITERS), 0.0, 0.0, 1.0); return color; } +fn trace_light(pos_view: vec4, dir_view: vec4) -> vec4 { + let gi = 0; + let group = voxel_groups[gi]; + if group.scale == 0 { + return vec4(0.0); + } + let dimensions = vec3(1u << group.scale); + let dim_f = vec3(dimensions); + let dim_i = vec3(dimensions); + + // transform so that group is at 0,0 + let pos_start = (group.transform_inv * pos_view).xyz; + var dir = (group.transform_inv * dir_view).xyz; + if dir.x == 0 {dir.x = EPSILON;} + if dir.y == 0 {dir.y = EPSILON;} + if dir.z == 0 {dir.z = EPSILON;} + + let dir_if = sign(dir); + let dir_uf = max(dir_if, vec3(0.0)); + + + + // calculate normals + var normals = mat3x3( + (group.transform * vec4(dir_if.x, 0.0, 0.0, 0.0)).xyz, + (group.transform * vec4(0.0, dir_if.y, 0.0, 0.0)).xyz, + (group.transform * vec4(0.0, 0.0, dir_if.z, 0.0)).xyz, + ); + var axis = 0u; + + // find where ray intersects with group + let pos_min = (vec3(1.0) - dir_uf) * dim_f; + // time of intersection; x = td + p, solve for t + var t_min = (pos_min - pos_start) / dir; + if outside3f(pos_start, ZERO3F, dim_f) { + // points of intersection + let px = pos_start + t_min.x * dir; + let py = pos_start + t_min.y * dir; + let pz = pos_start + t_min.z * dir; + + // 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_min > ZERO3F); + if !any(hit) { + return vec4(0.0); + } + axis = select(select(2u, 1u, hit.y), 0u, hit.x); + } + let t_mult = f32(1u << (MAX_SCALE - group.scale)); + t_min *= t_mult; + // time to move 1 unit in each direction + let full = f32(1u << MAX_SCALE); + let inc_t = abs(1.0 / dir) * full; + let t_offset = max(max(t_min.x, t_min.y), t_min.z); + var t = max(0.0, t_offset); + var old_t = t; + + let dir_i = vec3(dir_if); + let dir_u = vec3((dir_i + vec3(1)) / 2); + let dir_bits = vec_to_dir(dir_u); + let inv_dir_bits = 7 - dir_bits; + + var node_start = 1u; + var scale = MAX_SCALE - 1; + var scale_exp2 = 0.5; + var mask = vec4(0.0); + var skip = LEAF_BIT; + var parents = array(); + + var child = 0u; + var vox_pos = vec3(1.0); + let t_center = t_min + scale_exp2 * inc_t; + if t > t_center.x { vox_pos.x = 1.5; child |= 4u; } + if t > t_center.y { vox_pos.y = 1.5; child |= 2u; } + if t > t_center.z { vox_pos.z = 1.5; child |= 1u; } + let min_adj = t_min - inc_t; + var data = 0u; + + var iters = 0; + loop { + if iters == MAX_ITERS { + return vec4(1.0, 0.0, 1.0, 1.0); + } + iters += 1; + let t_corner = vox_pos * inc_t + min_adj; + let node = voxels[group.offset + node_start + (child ^ inv_dir_bits)]; + if node >= LEAF_BIT { + if node != skip && node != LEAF_BIT { + skip = node; + if data == 3 { + let dist = (t - old_t) / t_mult; + let vcolor = vec4(vec3(0.0), min(dist / 12.0, 1.0)); + mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); + } + data = node & LEAF_MASK; + if data != 3 && data != 0 { + let vcolor = get_color(data); + mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); + } + old_t = t; + if mask.a > FULL_ALPHA { break; } + } + + // move to next time point and determine which axis to move along + let t_next = t_corner + scale_exp2 * inc_t; + t = min(min(t_next.x, t_next.y), t_next.z); + axis = select(select(0u, 1u, t == t_next.y), 2u, t == t_next.z); + let move_dir = 4u >> axis; + + // check if need to pop stack + if (child & move_dir) > 0 { + // calculate new scale; first differing bit after adding + let axis_pos = vox_pos[axis]; + // AWARE + let differing = bitcast(axis_pos) ^ bitcast(axis_pos + scale_exp2); + scale = (bitcast(f32(differing)) >> 23) - 127 - (23 - MAX_SCALE); + scale_exp2 = bitcast((scale + 127 - MAX_SCALE) << 23); + if scale >= MAX_SCALE { break; } + + // restore & recalculate parent + let parent_info = parents[scale]; + node_start = parent_info >> 3; + child = parent_info & 7; + let scale_vec = vec3(scale + 23 - MAX_SCALE); + // remove bits lower than current scale + vox_pos = bitcast>((bitcast>(vox_pos) >> scale_vec) << scale_vec); + } + // move to next child and voxel position + child += move_dir; + vox_pos[axis] += scale_exp2; + } else { + // push current node to stack + parents[scale] = (node_start << 3) + child; + scale -= 1u; + + // calculate child node vars + scale_exp2 *= 0.5; + child = 0u; + let t_center = t_corner + scale_exp2 * inc_t; + if t > t_center.x { vox_pos.x += scale_exp2; child |= 4u; } + if t > t_center.y { vox_pos.y += scale_exp2; child |= 2u; } + if t > t_center.z { vox_pos.z += scale_exp2; child |= 1u; } + node_start += 8 + node; + } + } + if data == 3 { + let dist = (t - old_t) / t_mult; + let vcolor = vec4(vec3(0.0), min(dist / 12.0, 1.0)); + mask += vec4(vcolor.xyz * vcolor.a, vcolor.a) * (1.0 - mask.a); + } + mask.a = 1.0 - mask.a; + mask = vec4(mask.a * mask.xyz, mask.a); + return mask; +} + fn dir_to_vec(bits: u32) -> vec3 { return vec3(bits >> 2, (bits & 2) >> 1, bits & 1); } @@ -232,24 +386,19 @@ fn vec_to_dir(vec: vec3) -> u32 { return vec.x * 4 + vec.y * 2 + vec.z * 1; } -fn get_color(id: u32, pos: vec3) -> vec4 { - let random = random(pos); - let random2 = random(pos + vec3(0.0001)); +fn get_color(id: u32) -> vec4 { switch id { case 0u: { return vec4(0.0); } case 1u: { - let color = vec3(0.5, 0.5, 0.5 + random * 0.2) * (random2 * 0.4 + 0.8); - return vec4(color, 1.0); + return vec4(0.5, 0.5, 0.5, 1.0); } case 2u: { - let color = vec3(0.4 + random * 0.2, 0.9, 0.4 + random * 0.2) * (random2 * 0.2 + 0.9); - return vec4(color, 1.0); + return vec4(0.5, 1.0, 0.5, 1.0); } case 3u: { - let color = vec3(0.5, 0.5, 1.0) * (random2 * 0.2 + 0.8); - return vec4(color, 0.5); + return vec4(0.5, 0.5, 1.0, 0.5); } default: { return vec4(1.0, 0.0, 0.0, 1.0); @@ -257,10 +406,6 @@ fn get_color(id: u32, pos: vec3) -> vec4 { } } -fn random(pos: vec3) -> f32 { - return fract(sin(dot(pos,vec3(12.9898,78.233,25.1279)))*43758.5453123); -} - fn outside3f(v: vec3, low: vec3, high: vec3) -> bool { return any(v < low) || any(v > high); } diff --git a/src/common/component/chunk/mod.rs b/src/common/component/chunk/mod.rs index 2db49b8..6946910 100644 --- a/src/common/component/chunk/mod.rs +++ b/src/common/component/chunk/mod.rs @@ -8,7 +8,7 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{bundle::Bundle, component::Component, entity::Entity, system::Resource}; use nalgebra::Vector3; -pub const SCALE: u32 = 10; +pub const SCALE: u32 = 13; pub const SIDE_LENGTH: usize = 2usize.pow(SCALE); pub const SHAPE: (usize, usize, usize) = (SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH); pub const DIMENSIONS: Vector3 = Vector3::new(SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH); diff --git a/src/util/oct_tree.rs b/src/util/oct_tree.rs index ce46180..987e54c 100644 --- a/src/util/oct_tree.rs +++ b/src/util/oct_tree.rs @@ -1,13 +1,14 @@ -use std::fmt::Debug; +use std::{fmt::Debug, hash::Hash}; use nalgebra::Vector3; use ndarray::ArrayView3; +use rustc_hash::FxHashMap; const LEAF_BIT: u32 = 1 << 31; const DATA_OFFSET: usize = 8; #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable)] pub struct OctNode(u32); impl OctNode { pub const fn new_node(addr: u32) -> Self { @@ -30,9 +31,12 @@ impl OctNode { } } +type OctNodeMap = FxHashMap<[OctNode; 8], OctNode>; + #[derive(Debug, Clone)] pub struct OctTree { data: Vec, + map: OctNodeMap, levels: u32, side_length: usize, } @@ -52,6 +56,7 @@ impl OctTree { pub fn from_leaf(val: u32, levels: u32) -> Self { Self { data: vec![OctNode::new_leaf(val)], + map: FxHashMap::default(), side_length: 2usize.pow(levels), levels, } @@ -69,14 +74,17 @@ impl OctTree { levels: u32, offset: Vector3, ) -> Self { + assert!(levels > 0); let mut data = Vec::new(); + let mut map = OctNodeMap::default(); data.push(OctNode::new_node(0)); - Self::from_fn_offset_inner(f_leaf, f_node, &mut data, levels, offset); + Self::from_fn_offset_inner(f_leaf, f_node, &mut data, levels, offset, &mut map); if data.len() == 2 { data.remove(0); } Self { data, + map, side_length: 2usize.pow(levels), levels, } @@ -84,97 +92,57 @@ impl OctTree { fn from_fn_offset_inner( f_leaf: &mut impl FnMut(Vector3) -> u32, f_node: &mut impl FnMut(Vector3, u32) -> Option, - accumulator: &mut Vec, + data: &mut Vec, level: u32, offset: Vector3, + map: &mut OctNodeMap, ) { - if level == 0 { - accumulator.push(OctNode::new_leaf(f_leaf(offset))); - return; - } else if level == 1 { + if level == 1 { let leaves: [OctNode; 8] = core::array::from_fn(|i| OctNode::new_leaf(f_leaf(offset + CORNERS[i]))); if leaves[1..].iter().all(|l| *l == leaves[0]) { - accumulator.push(leaves[0]); + data.push(leaves[0]); + } else if let Some(node) = map.get(&leaves) { + data.push(*node); } else { - accumulator.extend_from_slice(&leaves); + data.extend_from_slice(&leaves); } return; } - let i = accumulator.len(); - accumulator.resize(i + 8, OctNode::new_node(0)); + let i = data.len(); + data.resize(i + 8, OctNode::new_node(0)); let mut data_start = 0; for (j, corner_offset) in CORNERS.iter().enumerate() { let lvl = level - 1; let pos = offset + corner_offset * 2usize.pow(lvl); - if let Some(node) = f_node(pos, lvl) { - accumulator[i + j] = OctNode::new_leaf(node); + if let Some(leaf) = f_node(pos, lvl) { + data[i + j] = OctNode::new_leaf(leaf); } else { - let sub_start = accumulator.len(); - Self::from_fn_offset_inner(f_leaf, f_node, accumulator, lvl, pos); - let len = accumulator.len() - sub_start; + let sub_start = data.len(); + Self::from_fn_offset_inner(f_leaf, f_node, data, lvl, pos, map); + let len = data.len() - sub_start; if len == 1 { - accumulator[i + j] = accumulator[sub_start]; - accumulator.pop(); + data[i + j] = data[sub_start]; + data.pop(); } else { - accumulator[i + j] = OctNode::new_node(data_start as u32); + let node = OctNode::new_node(sub_start as u32); + data[i + j] = node; data_start += len; + map.insert(data[sub_start..sub_start+8].try_into().unwrap(), node); } } } if data_start == 0 { - let first = accumulator[i]; - if accumulator[i + 1..i + 8].iter().all(|l| *l == first) { - accumulator.truncate(i); - accumulator.push(first); + let first = data[i]; + if first.is_leaf() && data[i + 1..i + 8].iter().all(|l| *l == first) { + data.truncate(i); + data.push(first); + } else if let Some(node) = map.get(&data[i..i + 8]) { + data.truncate(i); + data.push(*node); } } } - - pub fn from_fn_iter(f: &mut impl FnMut(Vector3) -> u32, levels: u32) -> Self { - let mut data = vec![OctNode::new_node(0)]; - let mut level: usize = 1; - let mut children = Vec::new(); - let mut child = vec![0; levels as usize + 1]; - let pows: Vec<_> = (0..levels).map(|l| 2usize.pow(l)).collect(); - while level < levels as usize { - if child[level] == 8 { - let i = children.len() - 8; - let first = children[i]; - if children[i + 1..].iter().all(|l| *l == first) { - children.truncate(i); - children.push(first); - } else { - data.extend_from_slice(&children[i..]); - children.truncate(i); - children.push(OctNode::new_node(data.len() as u32 - 8)); - } - child[level] = 0; - level += 1; - child[level] += 1; - } else if level == 1 { - let offset: Vector3 = (level..8).map(|l| CORNERS[child[l]] * pows[l]).sum(); - let leaves: [OctNode; 8] = - core::array::from_fn(|i| OctNode::new_leaf(f(offset + CORNERS[i]))); - if leaves[1..].iter().all(|l| *l == leaves[0]) { - children.push(leaves[0]); - } else { - children.push(OctNode::new_node(data.len() as u32)); - data.extend_from_slice(&leaves); - } - child[level] += 1; - } else { - level -= 1; - } - } - data[0] = children[0]; - Self { - data, - side_length: 2usize.pow(levels), - levels, - } - } - pub fn from_arr(arr: ArrayView3, levels: u32) -> Self { Self::from_fn_rec(&mut |p| arr[(p.x, p.y, p.z)], &mut |_, _| None, levels) }