diff --git a/Cargo.toml b/Cargo.toml index 0f0b018..0a6d36a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,13 +27,7 @@ blosc-src = { version = "0.3.0", features = ["lz4"] } bytemuck = { version = "1.13", features = ["extern_crate_alloc"] } byteorder = "1.4" flate2 = "1" -glam = ">=0.18,<=0.24" +glam = ">=0.18,<=0.30" half = { version = "2.2.1", features = ["bytemuck"] } log = "0.4" thiserror = "1" - -[dev-dependencies] -bevy = { version = "0.11", default-features = false, features = ["bevy_pbr"] } -bevy-aabb-instancing = "0.10" -bevy_egui = "0.22" -smooth-bevy-cameras = "0.9" diff --git a/README.md b/README.md index 630f9df..7fceb50 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,7 @@ Implementation of features however is use-case limited, so contributions in area # Broken files -These are test files from the OpenVDB website; . Most file seem to be loading correctly -and displaying correctly in the `bevy` example that's provided with this library. +These are test files from the OpenVDB website; . The only failing files are the ones containing a "points" grid. They all fail on `ParseError::InvalidNodeMetadata` which seem to be related to the lack of Multi-Pass I/O, though most need to be investigated. diff --git a/examples/bevy.rs b/examples/bevy.rs deleted file mode 100644 index adbc53c..0000000 --- a/examples/bevy.rs +++ /dev/null @@ -1,94 +0,0 @@ -use bevy::prelude::*; -use bevy_aabb_instancing::{ - Cuboid, CuboidMaterial, CuboidMaterialMap, Cuboids, ScalarHueOptions, - VertexPullingRenderPlugin, COLOR_MODE_SCALAR_HUE, -}; -use smooth_bevy_cameras::{controllers::unreal::*, LookTransformPlugin}; -use vdb_rs::VdbReader; - -use std::{error::Error, fs::File, io::BufReader}; - -fn main() -> Result<(), Box> { - App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "VDB Viewer".into(), - ..Default::default() - }), - ..Default::default() - })) - .add_plugins(VertexPullingRenderPlugin { outlines: true }) - .add_plugins(LookTransformPlugin) - .add_plugins(UnrealCameraPlugin::default()) - .add_systems(Startup, setup) - .run(); - - Ok(()) -} - -/// set up a simple 3D scene -fn setup(mut commands: Commands, mut color_options_map: ResMut) { - let color_options_id = color_options_map.push(CuboidMaterial { - color_mode: COLOR_MODE_SCALAR_HUE, - scalar_hue: ScalarHueOptions { - min_visible: -10000.0, - max_visible: 10000.0, - clamp_min: -1.0, - clamp_max: 0.5, - ..Default::default() - }, - ..Default::default() - }); - - let filename = std::env::args() - .nth(1) - .expect("Missing VDB filename as first argument"); - - let f = File::open(filename).unwrap(); - let mut vdb_reader = VdbReader::new(BufReader::new(f)).unwrap(); - let grid_names = vdb_reader.available_grids(); - - let grid_to_load = std::env::args().nth(2).unwrap_or_else(|| { - println!( - "Grid name not specified, defaulting to first available grid.\nAvailable grids: {:?}", - grid_names - ); - grid_names.first().cloned().unwrap_or(String::new()) - }); - - let grid = vdb_reader.read_grid::(&grid_to_load).unwrap(); - let instances: Vec = grid - .iter() - .map(|(pos, voxel, level)| { - Cuboid::new( - pos * 0.1, - (pos + level.scale()) * 0.1, - u32::from_le_bytes(f32::to_le_bytes(voxel.to_f32())), - ) - }) - .collect(); - let cuboids = Cuboids::new(instances); - let aabb = cuboids.aabb(); - commands - .spawn(SpatialBundle::default()) - .insert((cuboids, aabb, color_options_id)); - - commands.spawn(PointLightBundle { - point_light: PointLight { - intensity: 1500.0, - shadows_enabled: true, - ..default() - }, - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }); - - commands - .spawn(Camera3dBundle::default()) - .insert(UnrealCameraBundle::new( - UnrealCameraController::default(), - Vec3::new(0.0, 1.0, 10.0), - Vec3::ZERO, - Vec3::Y, - )); -} diff --git a/examples/slicer.rs b/examples/slicer.rs deleted file mode 100644 index 40656bc..0000000 --- a/examples/slicer.rs +++ /dev/null @@ -1,257 +0,0 @@ -use bevy::{prelude::*, render::primitives::Aabb}; -use bevy_aabb_instancing::{ - Cuboid, CuboidMaterial, CuboidMaterialId, CuboidMaterialMap, Cuboids, ScalarHueOptions, - VertexPullingRenderPlugin, COLOR_MODE_SCALAR_HUE, -}; -use bevy_egui::{egui, EguiContexts, EguiPlugin}; -use glam::vec3; -use half::f16; -use smooth_bevy_cameras::{ - controllers::orbit::{OrbitCameraBundle, OrbitCameraController, OrbitCameraPlugin}, - LookTransformPlugin, -}; -use vdb_rs::{Grid, Map, VdbLevel, VdbReader}; - -use std::{error::Error, fs::File, io::BufReader}; - -#[derive(Debug, PartialEq, Copy, Clone)] -enum SliceAxis { - X = 0, - Y, - Z, -} - -impl From for Vec3 { - fn from(value: SliceAxis) -> Self { - match value { - SliceAxis::X => Vec3::X, - SliceAxis::Y => Vec3::Y, - SliceAxis::Z => Vec3::Z, - } - } -} - -#[derive(Debug, PartialEq)] -enum RenderMode { - FirstDensity, - Tiles, - Slice(SliceAxis), -} - -#[derive(Resource)] -struct RenderSettings { - render_mode: RenderMode, - render_slice_index: i32, - min_slice_indices: IVec3, - max_slice_indices: IVec3, - dirty: bool, - visible_voxels: u64, -} - -#[derive(Resource)] -struct ModelData { - color_options_id: CuboidMaterialId, - grid: Grid, -} - -fn main() -> Result<(), Box> { - App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "VDB Viewer".into(), - ..Default::default() - }), - ..Default::default() - })) - .add_plugins(VertexPullingRenderPlugin { outlines: true }) - .add_plugins(LookTransformPlugin) - .add_plugins(OrbitCameraPlugin::default()) - .add_systems(Startup, setup) - .add_plugins(EguiPlugin) - .add_systems(Update, settings_ui) - .add_systems(Update, rebuild_model) - .run(); - - Ok(()) -} - -fn settings_ui(mut contexts: EguiContexts, mut settings: ResMut) { - egui::Window::new("Settings").show(contexts.ctx_mut(), |ui| { - egui::ComboBox::from_label("Render") - .selected_text(format!("{:?}", settings.render_mode)) - .show_ui(ui, |ui| { - settings.dirty |= ui - .selectable_value( - &mut settings.render_mode, - RenderMode::FirstDensity, - "Density", - ) - .changed(); - settings.dirty |= ui - .selectable_value(&mut settings.render_mode, RenderMode::Tiles, "Tiles") - .changed(); - settings.dirty |= ui - .selectable_value( - &mut settings.render_mode, - RenderMode::Slice(SliceAxis::X), - "X slice", - ) - .changed(); - settings.dirty |= ui - .selectable_value( - &mut settings.render_mode, - RenderMode::Slice(SliceAxis::Y), - "Y slice", - ) - .changed(); - settings.dirty |= ui - .selectable_value( - &mut settings.render_mode, - RenderMode::Slice(SliceAxis::Z), - "Z slice", - ) - .changed(); - }); - if let RenderMode::Slice(i) = settings.render_mode { - let range = - settings.min_slice_indices[i as usize]..=settings.max_slice_indices[i as usize]; - settings.dirty |= ui - .add(egui::Slider::new(&mut settings.render_slice_index, range)) - .changed() - } - ui.label(format!("visible voxels: {}", settings.visible_voxels)); - }); -} - -fn rebuild_model( - mut commands: Commands, - mut settings: ResMut, - model_data: Res, - existing_voxels: Query>, -) { - if settings.dirty { - existing_voxels.for_each(|entity| { - commands.entity(entity).despawn(); - }); - - let translation = match model_data.grid.transform { - Map::ScaleTranslateMap { translation, .. } => translation.as_vec3(), - _ => vec3(0.0, 0.0, 0.0), - }; - - let slice_index = settings.render_slice_index; - - let reject_fn: Box bool> = match settings.render_mode { - RenderMode::FirstDensity => Box::new(|_, _| false), - RenderMode::Slice(i) => Box::new(move |pos, _| pos[i as usize] as i32 != slice_index), - RenderMode::Tiles => Box::new(|_, level| level == VdbLevel::Voxel), - }; - - let instances: Vec = model_data - .grid - .iter() - .filter_map(|(mut pos, voxel, level)| { - // If our voxel intersects the slice index, we have to move it there to properly evaluate the reject_fn - let brick_starting_pos = ((pos / level.scale()).floor() - + if slice_index.is_negative() { 1.0 } else { 0.0 }) - * level.scale(); - let slice_local_offset = (slice_index % level.scale() as i32) as f32; - let level_invariate_position = brick_starting_pos + slice_local_offset; - if reject_fn(level_invariate_position, level) { - None - } else { - let mut dimension_mult = Vec3::ONE; - if let RenderMode::Slice(i) = settings.render_mode { - dimension_mult -= Vec3::from(i); - pos[i as usize] = slice_index as f32; - } - dimension_mult = (dimension_mult * level.scale()).max(Vec3::ONE); - - let pos = pos + translation; - Some(Cuboid::new( - pos * 0.1, - (pos + dimension_mult) * 0.1, - u32::from_le_bytes(f32::to_le_bytes(voxel.to_f32())), - )) - } - }) - .collect(); - - settings.visible_voxels = instances.len() as u64; - let cuboids = Cuboids::new(instances); - - let aabb = cuboids.aabb(); - commands.spawn(SpatialBundle::default()).insert(( - cuboids, - aabb, - model_data.color_options_id, - )); - settings.dirty = false; - } -} - -/// set up a simple 3D scene -fn setup(mut commands: Commands, mut color_options_map: ResMut) { - let grid = load_grid(); - - commands.insert_resource(RenderSettings { - render_mode: RenderMode::FirstDensity, - render_slice_index: 0, - min_slice_indices: grid.descriptor.aabb_min().unwrap(), - max_slice_indices: grid.descriptor.aabb_max().unwrap(), - dirty: true, - visible_voxels: 0, - }); - - commands.insert_resource(ModelData { - color_options_id: color_options_map.push(CuboidMaterial { - color_mode: COLOR_MODE_SCALAR_HUE, - scalar_hue: ScalarHueOptions { - min_visible: -10000.0, - max_visible: 10000.0, - clamp_min: -1.0, - clamp_max: 0.5, - ..Default::default() - }, - ..Default::default() - }), - grid, - }); - commands.spawn(PointLightBundle { - point_light: PointLight { - intensity: 1500.0, - shadows_enabled: true, - ..default() - }, - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }); - commands - .spawn(Camera3dBundle::default()) - .insert(OrbitCameraBundle::new( - OrbitCameraController::default(), - Vec3::new(0.0, 1.0, 10.0), - Vec3::ZERO, - Vec3::Y, - )); -} - -fn load_grid() -> Grid { - let filename = std::env::args() - .nth(1) - .expect("Missing VDB filename as first argument"); - - let f = File::open(filename.clone()).unwrap(); - let mut vdb_reader = VdbReader::new(BufReader::new(f)).unwrap(); - let grid_names = vdb_reader.available_grids(); - - let grid_to_load = std::env::args().nth(2).unwrap_or_else(|| { - println!( - "Grid name not specified, defaulting to first available grid.\nAvailable grids: {:?}", - grid_names - ); - grid_names.first().cloned().unwrap_or(String::new()) - }); - - vdb_reader.read_grid::(&grid_to_load).unwrap() -} diff --git a/src/data_structure.rs b/src/data_structure.rs index e45a5a4..a996982 100644 --- a/src/data_structure.rs +++ b/src/data_structure.rs @@ -219,7 +219,7 @@ impl Metadata { #[derive(Debug, Clone, PartialEq)] pub enum MetadataValue { String(String), - Vec3i(glam::IVec3), + Vec3i(IVec3), I32(i32), I64(i64), Float(f32), @@ -233,11 +233,8 @@ pub trait Node { const TOTAL: u32; fn local_coord_to_offset(&self, xyz: LocalCoord) -> Index { - Index( - (((xyz.0[0] & (Self::DIM - 1)) >> Self::TOTAL) << (2 * Self::LOG_2_DIM)) - + (((xyz.0[1] & (Self::DIM - 1)) >> Self::TOTAL) << Self::LOG_2_DIM) - + ((xyz.0[2] & (Self::DIM - 1)) >> Self::TOTAL), - ) + let index_3d = (xyz.0 & (Self::DIM - 1)) >> Self::TOTAL; + Index((index_3d.x << (2 * Self::LOG_2_DIM)) + (index_3d.y << Self::LOG_2_DIM) + index_3d.z) } fn offset_to_local_coord(&self, offset: Index) -> LocalCoord {