diff --git a/assets/models/minecraft_arc.vox b/assets/models/minecraft_arc.vox deleted file mode 100644 index e347d7e..0000000 Binary files a/assets/models/minecraft_arc.vox and /dev/null differ diff --git a/assets/models/minecraft_tree.vox b/assets/models/minecraft_tree.vox deleted file mode 100644 index 4cb280e..0000000 Binary files a/assets/models/minecraft_tree.vox and /dev/null differ diff --git a/assets/models/minecraft_tree_stem.vox b/assets/models/minecraft_tree_stem.vox deleted file mode 100644 index 08c1ebd..0000000 Binary files a/assets/models/minecraft_tree_stem.vox and /dev/null differ diff --git a/assets/models/monu1.vox b/assets/models/monu1.vox deleted file mode 100644 index 88e690f..0000000 Binary files a/assets/models/monu1.vox and /dev/null differ diff --git a/assets/models/teapot.vox b/assets/models/teapot.vox deleted file mode 100644 index fc73557..0000000 Binary files a/assets/models/teapot.vox and /dev/null differ diff --git a/assets/shaders/viewport_render.wgsl b/assets/shaders/viewport_render.wgsl index 8970f85..99eabe1 100644 --- a/assets/shaders/viewport_render.wgsl +++ b/assets/shaders/viewport_render.wgsl @@ -685,6 +685,30 @@ fn update( rgb_result = result_with_lights.rgb; } + /*// +++ DEBUG +++ + // Display the xyz axes + let root_hit = cube_intersect_ray( + Cube(vec3(0.,0.,0.), f32(octreeMetaData.octree_size)), ray + ); + if root_hit.hit == true { + if root_hit. impact_hit == true { + let axes_length = f32(octreeMetaData.octree_size) / 2.; + let axes_width = f32(octreeMetaData.octree_size) / 50.; + let entry_point = point_in_ray_at_distance(ray, root_hit.impact_distance); + if entry_point.x < axes_length && entry_point.y < axes_width && entry_point.z < axes_width { + rgb_result.r = 1.; + } + if entry_point.x < axes_width && entry_point.y < axes_length && entry_point.z < axes_width { + rgb_result.g = 1.; + } + if entry_point.x < axes_width && entry_point.y < axes_width && entry_point.z < axes_length { + rgb_result.b = 1.; + } + } + + } + */// --- DEBUG --- + textureStore(output_texture, pixel_location, vec4f(rgb_result, 1.)); } diff --git a/examples/minecraft.rs b/examples/minecraft.rs index 01af662..2e93085 100644 --- a/examples/minecraft.rs +++ b/examples/minecraft.rs @@ -35,12 +35,11 @@ fn main() { fn setup(mut commands: Commands, images: ResMut>) { // fill octree with data let tree; - let tree_path = "example_junk_minecraft_tree"; // instead of test_junk_octree - if false { - //std::path::Path::new(tree_path).exists() { + let tree_path = "example_junk_minecraft"; + if std::path::Path::new(tree_path).exists() { tree = Octree::::load(&tree_path).ok().unwrap(); } else { - tree = match shocovox_rs::octree::Octree::::load_magica_voxel_file( + tree = match shocovox_rs::octree::Octree::::load_vox_file( "assets/models/minecraft.vox", ) { Ok(tree_) => tree_, @@ -64,14 +63,14 @@ fn setup(mut commands: Commands, images: ResMut>) { let viewing_glass = create_viewing_glass( &Viewport { origin: V3c { - x: 6.15997, - y: 5.9686174, - z: 5.3837276, + x: 0., + y: 0., + z: 0., }, direction: V3c { - x: -0.6286289, - y: -0.5966367, - z: -0.49884903, + x: 0., + y: 0., + z: -1., }, w_h_fov: V3c::new(10., 10., 3.), }, @@ -109,7 +108,7 @@ fn rotate_camera( let radius = angles_query.single().radius; viewing_glass.viewport.origin = V3c::new( radius / 2. + yaw.sin() * radius, - radius / 2. + roll.sin() * radius, + radius + roll.sin() * radius * 2., radius / 2. + yaw.cos() * radius, ); viewing_glass.viewport.direction = @@ -132,13 +131,9 @@ fn handle_zoom( } }; if keys.pressed(KeyCode::ArrowUp) { - // viewing_glass.viewport.w_h_fov.x *= 1.1; - // viewing_glass.viewport.w_h_fov.y *= 1.1; angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, ADDITION); } if keys.pressed(KeyCode::ArrowDown) { - // viewing_glass.viewport.w_h_fov.x *= 0.9; - // viewing_glass.viewport.w_h_fov.y *= 0.9; angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, -ADDITION); } if keys.pressed(KeyCode::ArrowLeft) { @@ -151,11 +146,9 @@ fn handle_zoom( } if keys.pressed(KeyCode::PageUp) { angles_query.single_mut().radius *= 0.9; - // println!("viewport: {:?}", viewing_glass.viewport); } if keys.pressed(KeyCode::PageDown) { angles_query.single_mut().radius *= 1.1; - // println!("viewport: {:?}", viewing_glass.viewport); } } diff --git a/src/octree/convert/magicavoxel.rs b/src/octree/convert/magicavoxel.rs index b5806b7..e54e469 100644 --- a/src/octree/convert/magicavoxel.rs +++ b/src/octree/convert/magicavoxel.rs @@ -67,6 +67,7 @@ impl VoxelData for Color { /// Converts the given byte value to a rotation matrix /// Rotation matrix in voxel context enables 90 degr rotations only, so the contents of the matrix is restricted to 0,1,-1 +/// Takes into consideration, that the stored matrix is row-major, while Matrix3 storage is column major fn parse_rotation_matrix(b: u8) -> Matrix3 { let mut result = Matrix3::::new(0, 0, 0, 0, 0, 0, 0, 0, 0); @@ -87,9 +88,9 @@ fn parse_rotation_matrix(b: u8) -> Matrix3 { let sign_third_row = if 0 == (b & 0x40) { 1 } else { -1 }; // set the values in the matrix - result.data.0[0][index_in_first_row as usize] = sign_first_row; - result.data.0[1][index_in_second_row as usize] = sign_second_row; - result.data.0[2][index_in_third_row as usize] = sign_third_row; + result.data.0[index_in_first_row as usize][0] = sign_first_row; + result.data.0[index_in_second_row as usize][1] = sign_second_row; + result.data.0[index_in_third_row as usize][2] = sign_third_row; result } @@ -100,7 +101,7 @@ where { fn clone_transformed(&self, matrix: &Matrix3) -> V3c { V3c::new( - self.x * matrix.m11.into() + self.y * matrix.m21.into() + self.z * matrix.m31.into(), + self.x * matrix.m11.into() + self.y * matrix.m12.into() + self.z * matrix.m13.into(), self.x * matrix.m21.into() + self.y * matrix.m22.into() + self.z * matrix.m23.into(), self.x * matrix.m31.into() + self.y * matrix.m32.into() + self.z * matrix.m33.into(), ) @@ -129,12 +130,6 @@ fn iterate_vox_tree, &Matrix3) -> ()>( while 0 < node_stack.len() { let (current_node, translation, rotation, index) = *node_stack.last().unwrap(); - // println!("========================================================="); - // println!("node_stack size: {}", node_stack.len()); - // println!( - // "node: {}, translation: {:?}, index: {}", - // current_node, translation, index - // ); match &vox_tree.scenes[current_node as usize] { SceneNode::Transform { attributes: _, @@ -142,7 +137,6 @@ fn iterate_vox_tree, &Matrix3) -> ()>( child, layer_id: _, } => { - // println!("Processing translation"); let translation = if let Some(t) = frames[0].attributes.get("_t") { translation + t.split(" ") @@ -152,16 +146,7 @@ fn iterate_vox_tree, &Matrix3) -> ()>( } else { translation }; - // println!("orientation: {:?}", rotation,); let orientation = if let Some(r) = frames[0].attributes.get("_r") { - // println!( - // "orientation updated with: {:?}", - // parse_rotation_matrix(r.parse().unwrap()), - // ); - // println!( - // "updated orientation: {:?}", - // rotation * parse_rotation_matrix(r.parse().unwrap()), - // ); rotation * parse_rotation_matrix( r.parse() @@ -174,7 +159,6 @@ fn iterate_vox_tree, &Matrix3) -> ()>( if 0 == index { node_stack.push((*child, translation, orientation, 0)); } else { - // println!("pop"); // 0 != index ==> remove translation and iterate into parent node_stack.pop(); } @@ -183,7 +167,6 @@ fn iterate_vox_tree, &Matrix3) -> ()>( attributes: _, children, } => { - // println!("Processing Group[{index}] at {:?}", translation); if (index as usize) < children.len() { node_stack.last_mut().unwrap().3 += 1; node_stack.push((children[index as usize], translation, rotation, 0)); @@ -198,7 +181,6 @@ fn iterate_vox_tree, &Matrix3) -> ()>( attributes: _, models, } => { - // println!("Processing shape at {:?}", translation); for model in models { fun( &vox_tree.models[model.model_id as usize], @@ -219,124 +201,93 @@ impl Octree where T: Default + Eq + Clone + Copy + VoxelData, { - pub fn load_magica_voxel_file(filename: &str) -> Result { + pub fn load_vox_file(filename: &str) -> Result { let vox_tree = dot_vox::load(filename)?; - // println!("vox tree scenes: {:?}", vox_tree.scenes); - // let mut i = 0; - // for s in &vox_tree.scenes { - // println!("[{}] {:?}", i, s); - // i += 1; - // } - // println!("vox tree model sizes: "); - // i = 0; - // for s in &vox_tree.models { - // println!("[{}] {:?}", i, s.size); - // i += 1; - // } let mut min_position_lyup = V3c::::new(0, 0, 0); let mut max_position_lyup = V3c::::new(0, 0, 0); iterate_vox_tree(&vox_tree, |model, position, orientation| { - // println!("raw pos: {:?}", position); - let position = convert_coordinate( - V3c::from(*position), + let model_size_half_lyup = convert_coordinate( + V3c::from(model.size).clone_transformed(orientation), CoordinateSystemType::RZUP, CoordinateSystemType::LYUP, - ); - let model_size = convert_coordinate( - V3c::from(model.size).clone_transformed(orientation), + ) / 2; + + // If the index is negative, then it is calculated + // as model[size - i - 1][..][..], instead of model[i][..][..] + // So one needs to be added in every dimension where the index is below 0 + let position = convert_coordinate( + *position, CoordinateSystemType::RZUP, CoordinateSystemType::LYUP, + ) + V3c::new( + if model_size_half_lyup.x < 0 { -1 } else { 0 }, + if model_size_half_lyup.y < 0 { -1 } else { 0 }, + if model_size_half_lyup.z < 0 { -1 } else { 0 }, ); - // println!("orientation: {:?}", orientation); - // println!("converted pos: {:?}", position); - // println!( - // "model_size: {:?} --> {:?}", - // V3c::from(model.size), - // model_size - // ); - min_position_lyup.x = min_position_lyup.x.min(position.x - (model_size.x / 2)); - min_position_lyup.y = min_position_lyup.y.min(position.y - (model_size.y / 2)); - min_position_lyup.z = min_position_lyup.z.min(position.z - (model_size.z / 2)); - // println!("min position --> {:?}", min_position); - // println!("max pos: {:?} + {:?}", position, model_size); - if (position.x + model_size.x) > max_position_lyup.x - || (position.y + model_size.y) > max_position_lyup.y - || (position.z + model_size.z) > max_position_lyup.z - { - max_position_lyup = position + model_size; - } - // println!("max_position: {:?}", max_position_lyup); - // println!("min position: {:?}", min_position_lyup); + + min_position_lyup.x = min_position_lyup + .x + .min(position.x - model_size_half_lyup.x) + .min(position.x + model_size_half_lyup.x); + min_position_lyup.y = min_position_lyup + .y + .min(position.y - model_size_half_lyup.y) + .min(position.y + model_size_half_lyup.y); + min_position_lyup.z = min_position_lyup + .z + .min(position.z - model_size_half_lyup.z) + .min(position.z + model_size_half_lyup.z); + + max_position_lyup.x = max_position_lyup + .x + .max(position.x + model_size_half_lyup.x) + .max(position.x - model_size_half_lyup.x); + max_position_lyup.y = max_position_lyup + .y + .max(position.y + model_size_half_lyup.y) + .max(position.y - model_size_half_lyup.y); + max_position_lyup.z = max_position_lyup + .z + .max(position.z + model_size_half_lyup.z) + .max(position.z - model_size_half_lyup.z); }); max_position_lyup = max_position_lyup - min_position_lyup; - // println!("\nmax_position: {:?}", max_position_lyup); - // println!("min position: {:?}", min_position_lyup); let max_dimension = max_position_lyup .x .max(max_position_lyup.y) .max(max_position_lyup.z); let max_dimension = (max_dimension as f32).log2().ceil() as u32; let max_dimension = 2_u32.pow(max_dimension); - // println!("octree size: {max_dimension} \n ============================ \n "); let mut shocovox_octree = Octree::::new(max_dimension).ok().unwrap(); - let mut vmin = V3c::unit(max_dimension as u32); - let mut vmax = V3c::unit(0u32); iterate_vox_tree(&vox_tree, |model, position, orientation| { - let model_size_half_lyup = convert_coordinate( + let model_size_lyup = convert_coordinate( V3c::from(model.size).clone_transformed(orientation), CoordinateSystemType::RZUP, CoordinateSystemType::LYUP, - ) / 2; + ); let position = V3c::from(*position); - // println!("model_size: {:?}", model.size); - // println!("model_size_half: {:?}", V3c::from(model.size) / 2); - // println!( - // "m11: {:?}, m21: {:?}, m31: {:?}", - // orientation.m11, orientation.m21, orientation.m31 - // ); - // println!( - // "oriented model size: {:?}", - // V3c::from(model.size).clone_transformed(orientation) - // ); - // println!("oriented model_size_half_lyup: {:?}", model_size_half_lyup); - // println!("raw pos: {:?}", position); - // println!( - // "pos_lyup: {:?}", - // convert_coordinate( - // position, - // CoordinateSystemType::RZUP, - // CoordinateSystemType::LYUP, - // ) - // ); - // println!( - // "corrected position_lyup: {:?}", - // convert_coordinate( - // position, - // CoordinateSystemType::RZUP, - // CoordinateSystemType::LYUP, - // ) - min_position_lyup - // - model_size_half_lyup - // ); let position_lyup = convert_coordinate( position, CoordinateSystemType::RZUP, CoordinateSystemType::LYUP, ); - let current_position = position_lyup - min_position_lyup - model_size_half_lyup; + + let current_position = position_lyup - min_position_lyup - (model_size_lyup / 2) + + V3c::new( + if model_size_lyup.x < 0 { -1 } else { 0 }, + if model_size_lyup.y < 0 { -1 } else { 0 }, + if model_size_lyup.z < 0 { -1 } else { 0 }, + ); + + let mut vmin = V3c::unit(max_dimension as u32); + let mut vmax = V3c::unit(0u32); for voxel in &model.voxels { let voxel_position = convert_coordinate( V3c::from(*voxel).clone_transformed(orientation), CoordinateSystemType::RZUP, CoordinateSystemType::LYUP, ); - // println!( - // "{:?} + {:?} - ({:?}/2) = {:?} ", - // current_position, - // voxel_position, - // model_size_half_lyup * 2, - // current_position + voxel_position - // ); let cpos = current_position + voxel_position; if cpos.length() < vmin.length() { vmin = cpos.into(); @@ -353,10 +304,7 @@ where .ok() .unwrap(); } - // println!("model position: {:?}", current_position); - // println!("|min, max: {:?}, {:?}\n\n", vmin, vmax); }); - println!("Tree built from model!"); Ok(shocovox_octree) } } @@ -380,13 +328,12 @@ mod octree_tests { assert!(parsed_matrix.m33 == 1); // https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox-extension.txt - // Matrix3 storage is column major - let example = Matrix3::::new(0, 0, -1, 1, 0, 0, 0, -1, 0); - assert!( - parse_rotation_matrix((1 << 0) | (2 << 2) | (0 << 4) | (1 << 5) | (1 << 6)) == example - ); - assert!(example.m21 == 1); - assert!(example.m32 == -1); - assert!(example.m13 == -1); + let example = Matrix3::::new(0, 1, 0, 0, 0, -1, -1, 0, 0); + let parsed_example = + parse_rotation_matrix((1 << 0) | (2 << 2) | (0 << 4) | (1 << 5) | (1 << 6)); + assert!(parsed_example == example); + assert!(parsed_example.m12 == 1); + assert!(parsed_example.m23 == -1); + assert!(parsed_example.m31 == -1); } } diff --git a/src/spatial/math/vector.rs b/src/spatial/math/vector.rs index 1ede483..f9e087b 100644 --- a/src/spatial/math/vector.rs +++ b/src/spatial/math/vector.rs @@ -25,6 +25,18 @@ impl V3c { } } +impl V3c +where + T: num_traits::Signed + Clone, +{ + pub fn abs(&mut self) -> V3c { + self.x = self.x.abs(); + self.y = self.y.abs(); + self.z = self.z.abs(); + self.clone() + } +} + impl V3c { pub fn length(&self) -> f32 { ((self.x * self.x) + (self.y * self.y) + (self.z * self.z)).sqrt()