diff --git a/Cargo.toml b/Cargo.toml index a2d7df9..7988ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shocovox-rs" -version = "0.5.0" +version = "0.5.1" edition = "2021" authors = ["Dávid Tóth "] license = "MIT OR Apache-2.0" @@ -26,8 +26,9 @@ image = { version = "0.25.1", optional = true } show-image = { version = "0.14.0", optional = true } # for example bevy_wgpu -bevy = { version = "0.14.0", features = [], optional = true} -iyes_perf_ui = { version = "0.3.0", features = [], optional = true} +bevy = { version = "0.15.0", features = [], optional = true} +#iyes_perf_ui = { version = "0.3.0", features = [], optional = true} +iyes_perf_ui = { git = "https://github.com/IyesGames/iyes_perf_ui.git", features = [], optional = true} # debugging #linker = "/usr/bin/clang" diff --git a/assets/shaders/viewport_render.wgsl b/assets/shaders/viewport_render.wgsl index 96f714d..76ec83c 100644 --- a/assets/shaders/viewport_render.wgsl +++ b/assets/shaders/viewport_render.wgsl @@ -301,28 +301,6 @@ fn request_node(node_meta_index: u32, child_octant: u32) -> bool { return true; } -//crate::spatial::math::step_octant -fn step_octant(octant: u32, step: ptr) -> u32 { - return ( - ( - OCTANT_STEP_RESULT_LUT[u32(sign((*step).x) + 1)][u32(sign((*step).y) + 1)][u32(sign((*step).z) + 1)] - & (0x0Fu << (4 * octant)) - ) >> (4 * octant) - ) & 0x0Fu; -} - -//crate::spatial::math::hash_direction -fn hash_direction(direction: vec3f) -> u32 { - return hash_region(vec3f(1.) + normalize(direction), 1.); -} - -// Functionality-wise this function is more generic, than its counterpart -// and is used in voxel brick mapping too -//crate::spatial::math::flat_projection -fn flat_projection(i: vec3u, dimensions: vec2u) -> u32 { - return (i.x + (i.y * dimensions.y) + (i.z * dimensions.x * dimensions.y)); -} - struct BrickHit{ hit: bool, index: vec3u, @@ -377,7 +355,11 @@ fn traverse_brick( var mapped_index = ( brick_start_index * u32(dimension * dimension * dimension) - + flat_projection(vec3u(current_index), vec2u(u32(dimension), u32(dimension))) + + u32( //crate::spatial::math::flat_projection + current_index.x + + (current_index.y * dimension) + + (current_index.z * dimension * dimension) + ) ); if mapped_index >= arrayLength(&voxels) { @@ -537,7 +519,9 @@ fn traverse_node_for_ocbits( fn get_by_ray(ray: ptr) -> OctreeRayIntersection { var ray_scale_factors = get_dda_scale_factors(ray); // Should be const, but then it can't be passed as ptr - let direction_lut_index = hash_direction((*ray).direction); + let direction_lut_index = ( //crate::spatial::math::hash_direction + hash_region(vec3f(1.) + normalize((*ray).direction), 1.) + ); var node_stack: array; var node_stack_meta: u32 = 0; @@ -714,18 +698,27 @@ fn get_by_ray(ray: ptr) -> OctreeRayIntersection { if(EMPTY_MARKER != node_stack_last(node_stack_meta)){ current_node_key = node_stack[node_stack_last(node_stack_meta)]; current_node_meta = metadata[current_node_key]; - target_octant = step_octant( - hash_region( // parent current target octant - // current bound center - current_bounds.min_position + vec3f(round(current_bounds.size / 2.)) - - ( // parent bound min position - current_bounds.min_position - - (current_bounds.min_position % (current_bounds.size * 2.)) - ), - current_bounds.size + + // target octant updated to hold the target octant of the parent node temporarily + target_octant = hash_region( + // current bound center + current_bounds.min_position + vec3f(round(current_bounds.size / 2.)) + - ( // parent bound min position + current_bounds.min_position + - (current_bounds.min_position % (current_bounds.size * 2.)) ), - &step_vec + current_bounds.size ); + + // ..which is then stepped forward as if the parent was advancing + target_octant = ( //crate::spatial::math::step_octant + ( + OCTANT_STEP_RESULT_LUT[u32(sign(step_vec.x) + 1)] + [u32(sign(step_vec.y) + 1)] + [u32(sign(step_vec.z) + 1)] + & (0x0Fu << (4 * target_octant)) + ) >> (4 * target_octant) + ) & 0x0Fu; current_bounds.size = round(current_bounds.size * 2.); current_bounds.min_position -= current_bounds.min_position % current_bounds.size; } @@ -785,7 +778,14 @@ fn get_by_ray(ray: ptr) -> OctreeRayIntersection { &target_bounds, &ray_scale_factors )); - target_octant = step_octant(target_octant, &step_vec); + target_octant = ( //crate::spatial::math::step_octant + ( + OCTANT_STEP_RESULT_LUT[u32(sign(step_vec.x) + 1)] + [u32(sign(step_vec.y) + 1)] + [u32(sign(step_vec.z) + 1)] + & (0x0Fu << (4 * target_octant)) + ) >> (4 * target_octant) + ) & 0x0Fu; if OOB_OCTANT != target_octant { target_bounds = child_bounds_for(¤t_bounds, target_octant); target_child_key = node_children[(current_node_key * 8) + target_octant]; diff --git a/examples/dot_cube.rs b/examples/dot_cube.rs index 4516c7d..3a60105 100644 --- a/examples/dot_cube.rs +++ b/examples/dot_cube.rs @@ -9,7 +9,7 @@ use iyes_perf_ui::{ #[cfg(feature = "bevy_wgpu")] use shocovox_rs::octree::{ - raytracing::{OctreeGPUHost, OctreeGPUView, Ray, SvxViewSet, Viewport}, + raytracing::{OctreeGPUHost, Ray, SvxViewSet, Viewport}, Albedo, V3c, }; @@ -17,10 +17,10 @@ use shocovox_rs::octree::{ const DISPLAY_RESOLUTION: [u32; 2] = [1024, 768]; #[cfg(feature = "bevy_wgpu")] -const BRICK_DIMENSION: usize = 2; +const BRICK_DIMENSION: usize = 16; #[cfg(feature = "bevy_wgpu")] -const TREE_SIZE: u32 = 16; +const TREE_SIZE: u32 = 128; #[cfg(feature = "bevy_wgpu")] fn main() { @@ -102,7 +102,7 @@ fn setup(mut commands: Commands, images: ResMut>) { let mut views = SvxViewSet::default(); let output_texture = host.create_new_view( &mut views, - 40, + 45, Viewport { origin, direction: (V3c::new(0., 0., 0.) - origin).normalized(), @@ -113,15 +113,8 @@ fn setup(mut commands: Commands, images: ResMut>) { ); commands.insert_resource(host); commands.insert_resource(views); - commands.spawn(SpriteBundle { - sprite: Sprite { - custom_size: Some(Vec2::new(1024., 768.)), - ..default() - }, - texture: output_texture, - ..default() - }); - commands.spawn(Camera2dBundle::default()); + commands.spawn(Sprite::from_image(output_texture)); + commands.spawn(Camera2d::default()); commands.spawn(( PerfUiRoot::default(), PerfUiEntryFPS { @@ -148,11 +141,12 @@ struct DomePosition { yaw: f32, roll: f32, } + #[cfg(feature = "bevy_wgpu")] -fn rotate_camera(angles_query: Query<&mut DomePosition>, mut tree_view: ResMut) { +fn rotate_camera(angles_query: Query<&mut DomePosition>, view_set: ResMut) { let (yaw, roll) = (angles_query.single().yaw, angles_query.single().roll); let radius = angles_query.single().radius; - + let mut tree_view = view_set.views[0].lock().unwrap(); tree_view.spyglass.viewport.origin = V3c::new( radius / 2. + yaw.sin() * radius, radius + roll.sin() * radius * 2., @@ -165,10 +159,11 @@ fn rotate_camera(angles_query: Query<&mut DomePosition>, mut tree_view: ResMut>, - mut tree_view: ResMut, + tree: ResMut>, + view_set: ResMut, mut angles_query: Query<&mut DomePosition>, - tree: Res>, ) { + let mut tree_view = view_set.views[0].lock().unwrap(); const ADDITION: f32 = 0.05; let angle_update_fn = |angle, delta| -> f32 { let new_angle = angle + delta; @@ -240,12 +235,6 @@ fn handle_zoom( img.save("example_junk_cpu_render.png").ok().unwrap(); } - let multiplier = if keys.pressed(KeyCode::ShiftLeft) { - 10.0 // Doesn't have any effect?! - } else { - 1.0 - }; - if keys.pressed(KeyCode::ArrowUp) { angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, ADDITION); } @@ -259,18 +248,16 @@ fn handle_zoom( angles_query.single_mut().yaw = angle_update_fn(angles_query.single().yaw, -ADDITION); } if keys.pressed(KeyCode::PageUp) { - angles_query.single_mut().radius *= 1. - 0.02 * multiplier; + angles_query.single_mut().radius *= 1. - 0.02; } if keys.pressed(KeyCode::PageDown) { - angles_query.single_mut().radius *= 1. + 0.02 * multiplier; + angles_query.single_mut().radius *= 1. + 0.02; } if keys.pressed(KeyCode::Home) { - tree_view.spyglass.viewport.w_h_fov.x *= 1. + 0.09 * multiplier; - tree_view.spyglass.viewport.w_h_fov.y *= 1. + 0.09 * multiplier; + tree_view.spyglass.viewport.w_h_fov.z *= 1. + 0.09; } if keys.pressed(KeyCode::End) { - tree_view.spyglass.viewport.w_h_fov.x *= 1. - 0.09 * multiplier; - tree_view.spyglass.viewport.w_h_fov.y *= 1. - 0.09 * multiplier; + tree_view.spyglass.viewport.w_h_fov.z *= 1. - 0.09; } } diff --git a/examples/minecraft.rs b/examples/minecraft.rs index da49963..dcc695a 100644 --- a/examples/minecraft.rs +++ b/examples/minecraft.rs @@ -93,15 +93,8 @@ fn setup(mut commands: Commands, images: ResMut>) { ); commands.insert_resource(host); commands.insert_resource(views); - commands.spawn(SpriteBundle { - sprite: Sprite { - custom_size: Some(Vec2::new(1024., 768.)), - ..default() - }, - texture: output_texture, - ..default() - }); - commands.spawn(Camera2dBundle::default()); + commands.spawn(Sprite::from_image(output_texture)); + commands.spawn(Camera2d::default()); commands.spawn(( PerfUiRoot::default(), PerfUiEntryFPS { @@ -222,12 +215,6 @@ fn handle_zoom( img.save("example_junk_cpu_render.png").ok().unwrap(); } - let multiplier = if keys.pressed(KeyCode::ShiftLeft) { - 10.0 // Doesn't have any effect?! - } else { - 1.0 - }; - if keys.pressed(KeyCode::ArrowUp) { angles_query.single_mut().roll = angle_update_fn(angles_query.single().roll, ADDITION); } @@ -241,18 +228,16 @@ fn handle_zoom( angles_query.single_mut().yaw = angle_update_fn(angles_query.single().yaw, -ADDITION); } if keys.pressed(KeyCode::PageUp) { - angles_query.single_mut().radius *= 1. - 0.02 * multiplier; + angles_query.single_mut().radius *= 1. - 0.02; } if keys.pressed(KeyCode::PageDown) { - angles_query.single_mut().radius *= 1. + 0.02 * multiplier; + angles_query.single_mut().radius *= 1. + 0.02; } if keys.pressed(KeyCode::Home) { - tree_view.spyglass.viewport.w_h_fov.x *= 1. + 0.09 * multiplier; - tree_view.spyglass.viewport.w_h_fov.y *= 1. + 0.09 * multiplier; + tree_view.spyglass.viewport.w_h_fov.z *= 1. + 0.09; } if keys.pressed(KeyCode::End) { - tree_view.spyglass.viewport.w_h_fov.x *= 1. - 0.09 * multiplier; - tree_view.spyglass.viewport.w_h_fov.y *= 1. - 0.09 * multiplier; + tree_view.spyglass.viewport.w_h_fov.z *= 1. - 0.09; } } diff --git a/src/octree/raytracing/bevy/pipeline.rs b/src/octree/raytracing/bevy/pipeline.rs index 0c1fe4d..a7630c6 100644 --- a/src/octree/raytracing/bevy/pipeline.rs +++ b/src/octree/raytracing/bevy/pipeline.rs @@ -1,24 +1,25 @@ use crate::octree::{ raytracing::bevy::types::{ - OctreeRenderData, OctreeSpyGlass, SvxRenderNode, SvxRenderPipeline, Viewport, + OctreeMetaData, SvxRenderNode, SvxRenderPipeline, Viewport, Voxelement, }, VoxelData, }; - use bevy::{ asset::AssetServer, ecs::{ system::{Res, ResMut}, world::{FromWorld, World}, }, + prelude::Vec4, render::{ render_asset::RenderAssets, render_graph::{self}, render_resource::{ encase::{StorageBuffer, UniformBuffer}, - AsBindGroup, BindGroupEntry, BindingResource, BufferDescriptor, BufferInitDescriptor, - BufferUsages, CachedPipelineState, ComputePassDescriptor, ComputePipelineDescriptor, - PipelineCache, ShaderSize, + BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBindingType, + BufferDescriptor, BufferInitDescriptor, BufferUsages, CachedPipelineState, + ComputePassDescriptor, ComputePipelineDescriptor, PipelineCache, ShaderSize, + ShaderStages, ShaderType, StorageTextureAccess, TextureFormat, TextureViewDimension, }, renderer::{RenderContext, RenderDevice, RenderQueue}, texture::GpuImage, @@ -31,13 +32,112 @@ use super::types::{OctreeRenderDataResources, SvxViewSet}; impl FromWorld for SvxRenderPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let spyglass_bind_group_layout = OctreeSpyGlass::bind_group_layout(render_device); - let render_data_bind_group_layout = OctreeRenderData::bind_group_layout(render_device); + let spyglass_bind_group_layout = render_device.create_bind_group_layout( + "OctreeSpyGlass", + &[ + BindGroupLayoutEntry { + binding: 0u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::StorageTexture { + access: StorageTextureAccess::ReadWrite, + format: TextureFormat::Rgba8Unorm, + view_dimension: TextureViewDimension::D2, + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 1u32, + visibility: ShaderStages::all(), + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: Some(::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 2u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + ], + ); + let render_data_bind_group_layout = render_device.create_bind_group_layout( + "OctreeRenderData", + &[ + BindGroupLayoutEntry { + binding: 0u32, + visibility: ShaderStages::all(), + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: Some(::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 1u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 2u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 3u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 4u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + BindGroupLayoutEntry { + binding: 5u32, + visibility: ShaderStages::COMPUTE, + ty: BindingType::Buffer { + ty: BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: Some( as ShaderType>::min_size()), + }, + count: None, + }, + ], + ); let shader = world .resource::() .load("shaders/viewport_render.wgsl"); let pipeline_cache = world.resource::(); let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor { + zero_initialize_workgroup_memory: false, label: None, layout: vec![ spyglass_bind_group_layout.clone(), @@ -299,7 +399,7 @@ pub(crate) fn prepare_bind_groups( // Create bind group let tree_bind_group = render_device.create_bind_group( - OctreeRenderData::label(), + "OctreeRenderData", &pipeline.render_data_bind_group_layout, &[ bevy::render::render_resource::BindGroupEntry { @@ -389,7 +489,7 @@ pub(crate) fn prepare_bind_groups( .texture_view .clone(); let spyglass_bind_group = render_device.create_bind_group( - OctreeSpyGlass::label(), + "OctreeSpyGlass", &pipeline.spyglass_bind_group_layout, &[ BindGroupEntry { diff --git a/src/octree/raytracing/bevy/types.rs b/src/octree/raytracing/bevy/types.rs index 5841190..a203b76 100644 --- a/src/octree/raytracing/bevy/types.rs +++ b/src/octree/raytracing/bevy/types.rs @@ -3,10 +3,10 @@ use bevy::{ asset::Handle, ecs::system::Resource, math::Vec4, + prelude::Image, reflect::TypePath, render::{ extract_resource::ExtractResource, - prelude::Image, render_graph::RenderLabel, render_resource::{ AsBindGroup, BindGroup, BindGroupLayout, Buffer, CachedComputePipelineId, ShaderType, @@ -64,7 +64,7 @@ pub struct SvxViewSet { pub views: Vec>>, } -#[derive(Resource, Clone, AsBindGroup)] +#[derive(Resource, Clone)] pub struct OctreeGPUView { pub spyglass: OctreeSpyGlass, pub(crate) data_handler: OctreeGPUDataHandler, @@ -85,7 +85,7 @@ pub(crate) enum BrickOwnedBy { Node(u32, u8), } -#[derive(Resource, Clone, AsBindGroup)] +#[derive(Resource, Clone)] pub struct OctreeGPUDataHandler { pub(crate) render_data: OctreeRenderData, pub(crate) victim_node: VictimPointer, @@ -117,23 +117,17 @@ pub(crate) struct OctreeRenderDataResources { pub(crate) readable_metadata_buffer: Buffer, } -#[derive(Clone, AsBindGroup)] +#[derive(Clone)] pub struct OctreeSpyGlass { - #[storage_texture(0, image_format = Rgba8Unorm, access = ReadWrite)] pub output_texture: Handle, - - #[uniform(1, visibility(compute))] pub viewport: Viewport, - - #[storage(2, visibility(compute))] pub(crate) node_requests: Vec, } -#[derive(Clone, AsBindGroup, TypePath)] +#[derive(Clone, TypePath)] #[type_path = "shocovox::gpu::ShocoVoxRenderData"] pub struct OctreeRenderData { /// Contains the properties of the Octree - #[uniform(0, visibility(compute))] pub(crate) octree_meta: OctreeMetaData, /// Contains the properties of Nodes and Voxel Bricks @@ -171,7 +165,6 @@ pub struct OctreeRenderData { /// And only a fraction of them are visible in a render. /// *(4) Root node does not have this bit used, because it will never be overwritten /// due to the victim pointer logic - #[storage(1, visibility(compute))] pub(crate) metadata: Vec, /// Index values for Nodes, 8 value per @SizedNode entry. Each value points to: @@ -182,22 +175,18 @@ pub struct OctreeRenderData { /// ----------------------------------------- /// index of where the voxel brick start inside the @voxels buffer. /// Leaf node might contain 1 or 8 bricks according to @sized_node_meta, while - #[storage(2, visibility(compute))] pub(crate) node_children: Vec, /// Buffer of Node occupancy bitmaps. Each node has a 64 bit bitmap, /// which is stored in 2 * u32 values - #[storage(3, visibility(compute))] pub(crate) node_ocbits: Vec, /// Buffer of Voxel Bricks. Each brick contains voxel_brick_dim^3 elements. /// Each Brick has a corresponding 64 bit occupancy bitmap in the @voxel_maps buffer. - #[storage(4, visibility(compute))] pub(crate) voxels: Vec, /// Stores each unique color, it is references in @voxels /// and in @children_buffer as well( in case of solid bricks ) - #[storage(5, visibility(compute))] pub(crate) color_palette: Vec, }