Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolves #30 - Initial implementation of model import from Magica_voxel format #44

Merged
merged 7 commits into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ authors = ["Dávid Tóth <[email protected]>"]
license = "MIT OR Apache-2.0"

[features]
default = []
default = ["dot_vox_support"]
raytracing = ["dep:image", "dep:show-image"]
serialization = ["dep:serde"]
dot_vox_support = ["dep:dot_vox", "dep:nalgebra"]
bevy_wgpu = ["raytracing", "dep:bevy"]

[dependencies]
num-traits = "0.2.19"
serde = { version = "1.0.183", features = ["derive"], optional = true }
bendy = { git = "https://github.com/davids91/bendy.git" , features = ["std", "serde"]}
dot_vox = { version = "5.1.1", optional = true }
nalgebra = { version = "0.33.0", optional = true }

# for example cpu_render
image = { version = "0.25.1", optional = true }
show-image = { version = "0.14.0", optional = true }
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# Shocovox - Shady Octree Of Voxels with Ray Marching
Shocovox is a Sparse Voxel Octree implementation in GPU Shader Language(s) ( hence: shady ).
A basic implementation for raycasting/ray-marching is available, GPU support through various platforms is planned.
A basic implementation for raytracing is available with GPU support!

The library uses Left handed Y up coordinate system.

Features:
-

Special thanks to contributors and supporters!
@nerdachse For the Albedo type and amazing support!
@DouglasDwyer My nemesis; Check out [his project](https://github.com/DouglasDwyer/octo-release) it's amazing! ( I hate him )
Binary file added assets/models/minecraft.vox
Binary file not shown.
Binary file added assets/models/navigate.vox
Binary file not shown.
Binary file added assets/models/navigate_x.vox
Binary file not shown.
Binary file added assets/models/navigate_y.vox
Binary file not shown.
Binary file added assets/models/navigate_z.vox
Binary file not shown.
27 changes: 24 additions & 3 deletions assets/shaders/viewport_render.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,7 @@ fn get_by_ray(ray_: Line) -> OctreeRayIntersection{
);
node_stack_i = 1;
}

var i = 0.;
while(0 < node_stack_i && node_stack_i < max_depth) {
i += 1.;
var current_bounds = node_stack[node_stack_i - 1].bounds;
var current_node = nodes[node_stack[node_stack_i - 1].node]; //!NOTE: should be const, but then it can not be indexed dynamically
var target_octant = node_stack[node_stack_i - 1].target_octant;
Expand Down Expand Up @@ -688,6 +685,30 @@ fn update(
rgb_result = result_with_lights.rgb;
}

/*// +++ DEBUG +++
davids91 marked this conversation as resolved.
Show resolved Hide resolved
// 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.));
}

Expand Down
78 changes: 39 additions & 39 deletions examples/cpu_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use rand::Rng;

#[cfg(feature = "raytracing")]
use shocovox_rs::octree::{raytracing::Ray, V3c};
use shocovox_rs::octree::{raytracing::Ray, Octree, V3c};

#[cfg(feature = "raytracing")]
#[show_image::main]
Expand All @@ -14,32 +14,23 @@ fn main() {
const TREE_SIZE: u32 = 64;
let viewport_size_width = 150;
let viewport_size_height = 150;
let mut tree = shocovox_rs::octree::Octree::<Albedo, BRICK_DIMENSION>::new(TREE_SIZE)
.ok()
.unwrap();

tree.insert(&V3c::new(1, 3, 3), voxel_color)
.expect("insert of voxel to work");
for x in 0..TREE_SIZE {
for y in 0..TREE_SIZE {
for z in 0..TREE_SIZE {
if ((x < (TREE_SIZE / 4) || y < (TREE_SIZE / 4) || z < (TREE_SIZE / 4))
&& (0 == x % 2 && 0 == y % 4 && 0 == z % 2))
|| ((TREE_SIZE / 2) <= x && (TREE_SIZE / 2) <= y && (TREE_SIZE / 2) <= z)
{
tree.insert(
&V3c::new(x, y, z),
Albedo::default()
.with_red((255 as f32 * x as f32 / TREE_SIZE as f32) as u8)
.with_green((255 as f32 * y as f32 / TREE_SIZE as f32) as u8)
.with_blue((255 as f32 * z as f32 / TREE_SIZE as f32) as u8)
.with_alpha(255),
)
.ok()
.unwrap();
}
}
}
// let mut tree = shocovox_rs::octree::Octree::<Albedo, BRICK_DIMENSION>::new(TREE_SIZE)
davids91 marked this conversation as resolved.
Show resolved Hide resolved
// .ok()
// .unwrap();

let tree;
if std::path::Path::new("example_junk_minecraft_tree").exists() {
davids91 marked this conversation as resolved.
Show resolved Hide resolved
tree = Octree::<Albedo, 16>::load("example_junk_minecraft_tree")
.ok()
.unwrap();
} else {
tree = match shocovox_rs::octree::Octree::<Albedo, 16>::load_magica_voxel_file(
"assets/models/minecraft.vox",
) {
Ok(tree_) => tree_,
Err(message) => panic!("Parsing model file failed with message: {message}"),
};
tree.save("example_junk_minecraft_tree").ok().unwrap();
}

use shocovox_rs::octree::types::Albedo;
Expand Down Expand Up @@ -75,10 +66,17 @@ fn main() {
angle = angle + velos.x / 10.;

// Set the viewport
let origin = V3c::new(angle.sin() * radius, radius, angle.cos() * radius);
let viewport_ray = Ray {
direction: (V3c::unit(0.) - origin).normalized(),
origin,
origin: V3c {
davids91 marked this conversation as resolved.
Show resolved Hide resolved
x: 6.15997,
y: 5.9686174,
z: 5.3837276,
},
direction: V3c {
x: -0.6286289,
y: -0.5966367,
z: -0.49884903,
},
};
let viewport_up_direction = V3c::new(0., 1., 0.);
let viewport_right_direction = viewport_up_direction
Expand Down Expand Up @@ -137,15 +135,17 @@ fn main() {
}
}

use show_image::{ImageInfo, ImageView};
let binding = img.into_raw();
let image = ImageView::new(
ImageInfo::rgb8(viewport_size_width, viewport_size_height),
&binding,
);

// Create a window with default options and display the image.
window.set_image("image-001", image).ok().unwrap();
img.save("example_junk_cpu_render.png").ok().unwrap();
std::process::exit(0);
// use show_image::{ImageInfo, ImageView};
davids91 marked this conversation as resolved.
Show resolved Hide resolved
// let binding = img.into_raw();
// let image = ImageView::new(
// ImageInfo::rgb8(viewport_size_width, viewport_size_height),
// &binding,
// );

// // Create a window with default options and display the image.
// window.set_image("image-001", image).ok().unwrap();
}
}

Expand Down
159 changes: 159 additions & 0 deletions examples/minecraft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#[cfg(feature = "bevy_wgpu")]
use shocovox_rs::octree::Octree;

#[cfg(feature = "bevy_wgpu")]
use bevy::{prelude::*, window::WindowPlugin};

#[cfg(feature = "bevy_wgpu")]
use shocovox_rs::octree::{
raytracing::{
bevy::create_viewing_glass, ShocoVoxRenderPlugin, ShocoVoxViewingGlass, Viewport,
},
Albedo, V3c,
};

#[cfg(feature = "bevy_wgpu")]
const DISPLAY_RESOLUTION: [u32; 2] = [1024, 768];

#[cfg(feature = "bevy_wgpu")]
fn main() {
App::new()
.insert_resource(ClearColor(Color::BLACK))
.add_plugins((
DefaultPlugins.set(WindowPlugin::default()),
ShocoVoxRenderPlugin {
resolution: DISPLAY_RESOLUTION,
},
))
.add_systems(Startup, setup)
.add_systems(Update, rotate_camera)
.add_systems(Update, handle_zoom)
.run();
}

#[cfg(feature = "bevy_wgpu")]
fn setup(mut commands: Commands, images: ResMut<Assets<Image>>) {
// fill octree with data
let tree;
let tree_path = "example_junk_minecraft";
if std::path::Path::new(tree_path).exists() {
tree = Octree::<Albedo, 16>::load(&tree_path).ok().unwrap();
} else {
tree = match shocovox_rs::octree::Octree::<Albedo, 16>::load_vox_file(
"assets/models/minecraft.vox",
) {
Ok(tree_) => tree_,
Err(message) => panic!("Parsing model file failed with message: {message}"),
};
tree.save(&tree_path).ok().unwrap();
}

let origin = V3c::new(
tree.get_size() as f32 * 2.,
tree.get_size() as f32 / 2.,
tree.get_size() as f32 * -2.,
);
commands.spawn(DomePosition {
yaw: 0.,
roll: 0.,
radius: tree.get_size() as f32 * 2.2,
});

let render_data = tree.create_bevy_view();
let viewing_glass = create_viewing_glass(
&Viewport {
origin: V3c {
x: 0.,
y: 0.,
z: 0.,
},
direction: V3c {
x: 0.,
y: 0.,
z: -1.,
},
w_h_fov: V3c::new(10., 10., 3.),
},
DISPLAY_RESOLUTION,
images,
);
commands.spawn(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(1024., 768.)),
..default()
},
texture: viewing_glass.output_texture.clone(),
..default()
});
commands.spawn(Camera2dBundle::default());
commands.insert_resource(render_data);
commands.insert_resource(viewing_glass);
}

#[cfg(feature = "bevy_wgpu")]
#[derive(Component)]
struct DomePosition {
radius: f32,
yaw: f32,
roll: f32,
}

#[cfg(feature = "bevy_wgpu")]
fn rotate_camera(
angles_query: Query<&mut DomePosition>,
mut viewing_glass: ResMut<ShocoVoxViewingGlass>,
) {
let (yaw, roll) = (angles_query.single().yaw, angles_query.single().roll);

let radius = angles_query.single().radius;
viewing_glass.viewport.origin = V3c::new(
radius / 2. + yaw.sin() * radius,
radius + roll.sin() * radius * 2.,
radius / 2. + yaw.cos() * radius,
);
viewing_glass.viewport.direction =
(V3c::unit(radius / 2.) - viewing_glass.viewport.origin).normalized();
}

#[cfg(feature = "bevy_wgpu")]
fn handle_zoom(
keys: Res<ButtonInput<KeyCode>>,
mut viewing_glass: ResMut<ShocoVoxViewingGlass>,
mut angles_query: Query<&mut DomePosition>,
) {
const ADDITION: f32 = 0.05;
let angle_update_fn = |angle, delta| -> f32 {
let new_angle = angle + delta;
if new_angle < 360. {
new_angle
} else {
0.
}
};
if keys.pressed(KeyCode::ArrowUp) {
angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, ADDITION);
}
if keys.pressed(KeyCode::ArrowDown) {
angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, -ADDITION);
}
if keys.pressed(KeyCode::ArrowLeft) {
angles_query.single_mut().yaw = angle_update_fn(angles_query.single().yaw, ADDITION);
// println!("viewport: {:?}", viewing_glass.viewport);
}
if keys.pressed(KeyCode::ArrowRight) {
angles_query.single_mut().yaw = angle_update_fn(angles_query.single().yaw, -ADDITION);
// println!("viewport: {:?}", viewing_glass.viewport);
}
if keys.pressed(KeyCode::PageUp) {
angles_query.single_mut().radius *= 0.9;
}
if keys.pressed(KeyCode::PageDown) {
angles_query.single_mut().radius *= 1.1;
}
}

#[cfg(not(feature = "bevy_wgpu"))]
fn main() {
println!("You probably forgot to enable the bevy_wgpu feature!");
//nothing to do when the feature is not enabled
}
10 changes: 5 additions & 5 deletions src/octree/bytecode.rs → src/octree/convert/bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::object_pool::ObjectPool;
use crate::octree::types::{NodeChildren, NodeChildrenArray, NodeContent, Octree, VoxelData};
use crate::octree::{
types::{NodeChildren, NodeChildrenArray, NodeContent},
Albedo, Octree, VoxelData,
};
use bendy::{
decoding::ListDecoder,
decoding::{FromBencode, ListDecoder, Object},
encoding::{Encoder, Error as BencodeError, SingleItemEncoder, ToBencode},
};

Expand Down Expand Up @@ -84,9 +87,6 @@ where
}
}

use bendy::decoding::{FromBencode, Object};

use super::types::Albedo;
impl<T, const DIM: usize> FromBencode for NodeContent<T, DIM>
where
T: Eq + Default + Clone + Copy + VoxelData,
Expand Down
Loading
Loading