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 #20 - Migrated GPU implementation from fragment shader to compute shaders #31

Merged
merged 5 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shocovox-rs"
version = "0.2.2"
version = "0.3.0"
edition = "2021"
authors = ["Dávid Tóth <[email protected]>"]
license = "MIT OR Apache-2.0"
Expand Down
41 changes: 24 additions & 17 deletions assets/shaders/viewport_render.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -671,36 +671,42 @@ struct Viewport {
fov: f32,
}

@group(2) @binding(0)
@group(0) @binding(1)
davids91 marked this conversation as resolved.
Show resolved Hide resolved
var output_texture: texture_storage_2d<rgba8unorm, read_write>;

@group(0) @binding(2)
var<uniform> viewport: Viewport;

@group(2) @binding(1)
@group(0) @binding(3)
var<uniform> octreeMetaData: OctreeMetaData;

@group(2) @binding(2)
@group(0) @binding(4)
var<storage, read_write> nodes: array<SizedNode>;

@group(2) @binding(3)
@group(0) @binding(5)
var<storage, read_write> voxels: array<Voxelement>;

@fragment
fn fragment(mesh: VertexOutput) -> @location(0) vec4<f32> {
let viewport_ = viewport; //Read only once from global RAM
davids91 marked this conversation as resolved.
Show resolved Hide resolved
@compute @workgroup_size(8, 8, 1)
fn update(@builtin(global_invocation_id) invocation_id: vec3<u32>) {
let pixel_location = vec2u(invocation_id.xy);
let pixel_location_normalized = vec2f(
f32(invocation_id.x) / 640.,
f32(invocation_id.y) / 480.
);
let viewport_up_direction = vec3f(0., 1., 0.);
let viewport_right_direction = normalize(cross(
viewport_up_direction, viewport_.direction
viewport_up_direction, viewport.direction
));
let
viewport_bottom_left = viewport_.origin
+ (viewport_.direction * viewport_.fov)
- (viewport_right_direction * (viewport_.size.x / 2.))
- (viewport_up_direction * (viewport_.size.y / 2.))
let viewport_bottom_left = viewport.origin
+ (viewport.direction * viewport.fov)
- (viewport_right_direction * (viewport.size.x / 2.))
- (viewport_up_direction * (viewport.size.y / 2.))
;
let ray_endpoint = viewport_bottom_left
+ viewport_right_direction * viewport_.size.x * mesh.uv.x
+ viewport_up_direction * viewport_.size.y * (1. - mesh.uv.y)
+ viewport_right_direction * viewport.size.x * f32(pixel_location_normalized.x)
+ viewport_up_direction * viewport.size.y * (1. - f32(pixel_location_normalized.y))
;
var ray = Line(ray_endpoint, normalize(ray_endpoint - viewport_.origin));
var ray = Line(ray_endpoint, normalize(ray_endpoint - viewport.origin));

var ray_result = get_by_ray(ray);
var rgb_result = vec3f(0.5,0.5,0.5);
Expand All @@ -711,7 +717,8 @@ fn fragment(mesh: VertexOutput) -> @location(0) vec4<f32> {
let result_with_lights = ray_result.albedo.rgb * diffuse_light_strength;
rgb_result = result_with_lights.rgb;
}
return vec4<f32>(rgb_result, 1.0);

textureStore(output_texture, pixel_location, vec4f(rgb_result, 1.));
}

// Note: should be const
Expand Down
147 changes: 56 additions & 91 deletions examples/bevy_wgpu_render.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,33 @@
#[cfg(feature = "bevy_wgpu")]
use bevy::prelude::*;
#[cfg(feature = "bevy_wgpu")]
use shocovox_rs::{octree::raytracing::OctreeViewMaterial, octree::V3c};
use bevy::{prelude::*, window::WindowPlugin};
use shocovox_rs::octree::{
raytracing::{ShocoVoxRenderPlugin, ShocoVoxViewingGlass, Viewport},
V3c,
};

const RESOLUTION: [u32; 2] = [320, 240];

#[cfg(feature = "bevy_wgpu")]
fn main() {
App::new()
.insert_resource(ClearColor(Color::BLACK))
.add_plugins((
DefaultPlugins,
MaterialPlugin::<OctreeViewMaterial>::default(),
DefaultPlugins.set(WindowPlugin::default()),
ShocoVoxRenderPlugin {
resolution: RESOLUTION,
},
davids91 marked this conversation as resolved.
Show resolved Hide resolved
))
.add_systems(Startup, setup)
.add_systems(Update, rotate_camera)
.add_systems(Update, handle_zoom)
.run();
}

#[cfg(feature = "bevy_wgpu")]
const ARRAY_DIMENSION: u32 = 64;

#[cfg(feature = "bevy_wgpu")]
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<OctreeViewMaterial>>,
) {
use shocovox_rs::octree::raytracing::Viewport;

commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 3000.0,
..Default::default()
},
transform: Transform::from_xyz(-3.0, 2.0, -1.0),
..Default::default()
});
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 3000.0,
..Default::default()
},
transform: Transform::from_xyz(3.0, 2.0, 1.0),
..Default::default()
});

commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(5.0, 5.0, 7.0).looking_at(Vec3::new(4., 1., 0.0), Vec3::Y),
..Default::default()
});

fn setup(mut commands: Commands, images: ResMut<Assets<Image>>) {
let origin = Vec3::new(
ARRAY_DIMENSION as f32 * 2.,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 * -2.,
);
commands.spawn(DomePosition { yaw: 0. });

// fill octree with data
Expand Down Expand Up @@ -90,42 +69,36 @@ fn setup(
}
}
}
let quad_count = 1;
let quad_size = 10. / quad_count as f32;
let mesh_handle = meshes.add(Mesh::from(Rectangle {
half_size: Vec2::new(quad_size, quad_size) / 2.,
}));
let origin = Vec3::new(
ARRAY_DIMENSION as f32 * 2.,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 * -2.,
let viewing_glass = tree.create_bevy_view(
&Viewport {
direction: (Vec3::new(0., 0., 0.) - origin).normalize(),
origin,
size: Vec2::new(10., 10.),
fov: 3.,
},
RESOLUTION,
images,
);
let material_handle = materials.add(tree.create_bevy_material_view(&Viewport {
direction: (Vec3::new(0., 0., 0.) - origin).normalize(),
origin,
size: Vec2::new(10., 10.),
fov: 3.,
}));
for x in 0..quad_count {
commands.spawn(MaterialMeshBundle {
mesh: mesh_handle.clone(),
material: material_handle.clone(),
transform: Transform::from_xyz((x as f32 * quad_size) + 0.5, x as f32 / 5., 0.0),
..Default::default()
});
}
commands.spawn(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(RESOLUTION[0] as f32, RESOLUTION[1] as f32)),
..default()
},
texture: viewing_glass.output_texture.clone(),
..default()
});
commands.spawn(Camera2dBundle::default());
commands.insert_resource(viewing_glass);
}

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

#[cfg(feature = "bevy_wgpu")]
fn rotate_camera(
mut angles_query: Query<&mut DomePosition>,
mut mats: ResMut<Assets<OctreeViewMaterial>>,
mut viewing_glass: ResMut<ShocoVoxViewingGlass>,
) {
let angle = {
let addition = ARRAY_DIMENSION as f32 / 1024.;
Expand All @@ -138,33 +111,25 @@ fn rotate_camera(
};
angles_query.single_mut().yaw = angle;

for (_mat_handle, mat) in mats.as_mut().iter_mut() {
let radius = ARRAY_DIMENSION as f32 * 1.3;
mat.viewport.origin = Vec3::new(
ARRAY_DIMENSION as f32 / 2. + angle.sin() * radius,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2. + angle.cos() * radius,
);
mat.viewport.direction = (Vec3::new(
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2.,
) - mat.viewport.origin)
.normalize();
}
let radius = ARRAY_DIMENSION as f32 * 1.3;
viewing_glass.viewport.origin = Vec3::new(
ARRAY_DIMENSION as f32 / 2. + angle.sin() * radius,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2. + angle.cos() * radius,
);
viewing_glass.viewport.direction = (Vec3::new(
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2.,
ARRAY_DIMENSION as f32 / 2.,
) - viewing_glass.viewport.origin)
.normalize();
}

#[cfg(feature = "bevy_wgpu")]
fn handle_zoom(keys: Res<ButtonInput<KeyCode>>, mut mats: ResMut<Assets<OctreeViewMaterial>>) {
for (_mat_handle, mat) in mats.as_mut().iter_mut() {
if keys.pressed(KeyCode::ArrowUp) {
mat.viewport.size *= 1.1;
}
if keys.pressed(KeyCode::ArrowDown) {
mat.viewport.size *= 0.9;
}
fn handle_zoom(keys: Res<ButtonInput<KeyCode>>, mut viewing_glass: ResMut<ShocoVoxViewingGlass>) {
if keys.pressed(KeyCode::ArrowUp) {
viewing_glass.viewport.size *= 1.1;
}
if keys.pressed(KeyCode::ArrowDown) {
viewing_glass.viewport.size *= 0.9;
}
}

#[cfg(not(feature = "bevy_wgpu"))]
fn main() {} //nothing to do when the feature is not enabled
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
use crate::object_pool::empty_marker;

use crate::octree::{
raytracing::types::{OctreeMetaData, OctreeViewMaterial, SizedNode, Viewport, Voxelement},
raytracing::{
bevy::create_ouput_texture,
types::{OctreeMetaData, ShocoVoxViewingGlass, SizedNode, Viewport, Voxelement},
ShocoVoxRenderPlugin,
},
types::{NodeChildrenArray, NodeContent},
Octree, VoxelData,
};

use bevy::{
math::Vec3,
pbr::Material,
render::{color::Color, render_resource::ShaderRef},
asset::Assets, ecs::system::ResMut, math::Vec3, render::color::Color, render::texture::Image,
};

impl Material for OctreeViewMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/viewport_render.wgsl".into()
}
}

use crate::octree::{Octree, VoxelData};
impl<T, const DIM: usize> Octree<T, DIM>
where
T: Default + Clone + VoxelData,
Expand Down Expand Up @@ -58,7 +55,12 @@ where
meta
}

pub fn create_bevy_material_view(&self, viewport: &Viewport) -> OctreeViewMaterial {
pub fn create_bevy_view(
&self,
viewport: &Viewport,
resolution: [u32; 2],
images: ResMut<Assets<Image>>,
) -> ShocoVoxViewingGlass {
let meta = OctreeMetaData {
octree_size: self.octree_size,
voxel_matrix_dim: DIM as u32,
Expand Down Expand Up @@ -113,7 +115,9 @@ where
}
nodes.push(sized_node);
}
OctreeViewMaterial {

ShocoVoxViewingGlass {
output_texture: create_ouput_texture(resolution, images),
viewport: *viewport,
meta,
nodes,
Expand Down
Loading
Loading