diff --git a/Cargo.toml b/Cargo.toml index 040a9a9..1f13205 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,10 @@ [package] -name = "rust_opengl" +name = "rustray" edition = "2018" version = "0.1.0" authors = ["hodasemi "] [dependencies] -sdl2 = "0.30" cgmath = "*" -utilities = { path = "../../Gavania/utilities" } -image = "*" \ No newline at end of file +utilities = { git = "https://gitlab.com/hodasemi/utilities.git" } +image = "*" diff --git a/src/aabb.rs b/src/aabb.rs index 41cc9fe..3e09b0f 100644 --- a/src/aabb.rs +++ b/src/aabb.rs @@ -2,18 +2,23 @@ use cgmath::{Vector3, Zero}; use super::ray::Ray; +#[derive(Clone, Copy, Debug)] pub struct AABB { pub bounds: [Vector3; 2], - pub start_index: usize, - pub end_index: usize, + pub start_index: isize, + pub end_index: isize, + pub left_child: isize, + pub right_child: isize, } impl AABB { pub fn new() -> AABB { AABB { bounds: [Vector3::zero(), Vector3::zero()], - start_index: 0, - end_index: 0, + start_index: -1, + end_index: -1, + left_child: -1, + right_child: -1, } } diff --git a/src/acceleration_data.rs b/src/acceleration_data.rs new file mode 100644 index 0000000..c90ef51 --- /dev/null +++ b/src/acceleration_data.rs @@ -0,0 +1,165 @@ +use cgmath::{vec2, vec3, Vector2, Vector3, Zero}; + +use std::f32::{MAX, MIN}; + +use crate::aabb::AABB; +use crate::intersection::Intersection; +use crate::ray::Ray; +use crate::triangle::Triangle; + +pub struct AccelerationData<'a> { + triangles: &'a [Triangle], + data: [AABB; 1024], +} + +impl<'a> AccelerationData<'a> { + pub fn create_tree(input_data: &'a [Triangle], triangles_per_as: u32) -> Self { + // we are creating the tree from the bottom up + + // create our slice + let mut data = [AABB::new(); 1024]; + + // first lets create the leaf nodes + let leaf_nodes = Self::create_leaf_nodes(input_data, triangles_per_as); + + // copy leaf nodes into our final array + for (index, aabb) in leaf_nodes.iter().enumerate() { + data[index + 1] = *aabb; + } + + // create complete tree from leaf nodes + Self::create_tree_nodes(&mut data, leaf_nodes.len() as u32); + + // return result + AccelerationData { + triangles: input_data, + data, + } + } + + pub fn find_closest_hit(&self, ray: &Ray) -> Option { + None + } + + pub fn print_tree(&self) { + let mut discovered = vec![false; 1024]; + let mut stack = Vec::new(); + + // push root node + stack.push(0); + + while !stack.is_empty() { + let v = stack.pop().unwrap(); + + if discovered[v] { + continue; + } + + discovered[v] = true; + + println!("{}\n{:?}", v, self.data[v]); + } + } +} + +// private +impl<'a> AccelerationData<'a> { + fn create_leaf_nodes(input_data: &[Triangle], triangles_per_as: u32) -> Vec { + let mut acceleration_data = Vec::new(); + + let accel_count = (input_data.len() as f32 / triangles_per_as as f32).ceil() as usize; + + for i in 0..accel_count { + let mut accel = AABB::new(); + + let mut bbmin = vec3(MAX, MAX, MAX); + let mut bbmax = vec3(MIN, MIN, MIN); + + // 3 vertices per triangles + // 8 triangles per acceleration structure + let start_index = triangles_per_as as usize * i; + let mut end_index = triangles_per_as as usize * (i + 1); + + // check if end_index exceeds input data length + if end_index > input_data.len() { + end_index = input_data.len(); + } + + // set index information + accel.start_index = start_index as isize; + accel.end_index = end_index as isize; + + // create bounding box + for k in start_index..end_index { + for vertex in input_data[k].vertices.iter() { + // check minimum values + bbmin.x = bbmin.x.min(vertex.position.x); + bbmin.y = bbmin.y.min(vertex.position.y); + bbmin.z = bbmin.z.min(vertex.position.z); + + // check maximum values + bbmax.x = bbmax.x.max(vertex.position.x); + bbmax.y = bbmax.y.max(vertex.position.y); + bbmax.z = bbmax.z.max(vertex.position.z); + } + } + + accel.bounds[0] = bbmin; + accel.bounds[1] = bbmax; + + acceleration_data.push(accel); + } + + acceleration_data + } + + fn create_tree_nodes(data: &mut [AABB], leaf_node_count: u32) { + let mut current_level_count = leaf_node_count; + let mut start_index = 1; + + loop { + let odd = (current_level_count % 2) == 1; + let next_level_count = (current_level_count as f32 / 2.0).ceil() as u32; + let next_level_start = start_index + current_level_count; + + for i in next_level_start..(next_level_start + next_level_count) { + let mut aabb = AABB::new(); + + let index = (start_index + i * 2) as usize; + + if i == (next_level_count + next_level_start - 1) && odd { + aabb.bounds[0] = data[index].bounds[0]; + aabb.bounds[1] = data[index].bounds[1]; + aabb.left_child = index as isize; + } else { + aabb.bounds[0] = Self::min(data[index].bounds[0], data[index + 1].bounds[0]); + aabb.bounds[1] = Self::max(data[index].bounds[1], data[index + 1].bounds[1]); + aabb.left_child = index as isize; + aabb.right_child = index as isize + 1; + } + + if next_level_count == 1 { + data[0] = aabb; + break; + } else { + data[i as usize] = aabb; + } + } + + if next_level_count == 1 { + break; + } + + current_level_count = next_level_count; + start_index = next_level_start; + } + } + + fn min(v0: Vector3, v1: Vector3) -> Vector3 { + Vector3::new(v0.x.min(v1.x), v0.y.min(v1.y), v0.z.min(v1.z)) + } + + fn max(v0: Vector3, v1: Vector3) -> Vector3 { + Vector3::new(v0.x.max(v1.x), v0.y.max(v1.y), v0.z.max(v1.z)) + } +} diff --git a/src/emi_codierung.rs b/src/emi_codierung.rs deleted file mode 100644 index bb8f53c..0000000 --- a/src/emi_codierung.rs +++ /dev/null @@ -1,54 +0,0 @@ -fn part(p_i: f32) -> f32 { - p_i * p_i.log2() -} - -fn coded_length(table: &[(char, f32, &str, &str)], word: &str) -> u32 { - let mut length_in_bit = 0; - - for letter in word.chars() { - let (_l, _p, _f, huffman_word) = table - .iter() - .find(|(t_letter, _p, _fano, _huffman)| letter == *t_letter) - .expect("letter not found in table"); - - length_in_bit += huffman_word.len() as u32; - } - - length_in_bit -} - -pub fn emi_main() { - // word, probability, fano, huffman - - let values = [ - ('V', 0.65, "0", "0"), - ('Z', 0.11, "100", "100"), - ('B', 0.05, "101", "1010"), - ('E', 0.05, "1100", "1011"), - ('T', 0.04, "1101", "1100"), - ('>', 0.04, "1110", "1101"), - ('<', 0.04, "11110", "1110"), - ('S', 0.02, "11110", "1111"), - ]; - - let mut h = 0.0; - let mut huffman_l = 0.0; - let mut fano_l = 0.0; - - for (_name, probability, fano, huffman) in values.iter() { - h -= part(*probability); - huffman_l += *probability * huffman.len() as f32; - fano_l += *probability * fano.len() as f32; - } - - let huffman_r = huffman_l - h; - - println!("Entropie H = {}", h); - println!("Mittlere Wortlänge L(Huffman) = {}", huffman_l); - println!("Mittlere Wortlänge L(fano) = {}", fano_l); - println!("Redundanz R(Huffman) = {}", huffman_r); - - let code_length = coded_length(&values, "BVVVZVVVVVSSVVE"); - - println!("Length in Huffman = {}", code_length); -} diff --git a/src/intersection.rs b/src/intersection.rs new file mode 100644 index 0000000..bce116d --- /dev/null +++ b/src/intersection.rs @@ -0,0 +1,29 @@ +use cgmath::{vec2, vec3, Vector2, Vector3, Zero}; + +use crate::triangle::Triangle; + +use std::f32::MAX; + +pub struct Intersection { + pub distance: f32, + pub triangle: Triangle, + pub barycentric: Vector2, +} + +impl Intersection { + pub fn new(distance: f32, triangle: Triangle, barycentric: Vector2) -> Intersection { + Intersection { + distance, + triangle, + barycentric, + } + } + + pub fn zero() -> Intersection { + Intersection { + distance: MAX, + triangle: Triangle::zero(), + barycentric: Vector2::zero(), + } + } +} diff --git a/src/main.rs b/src/main.rs index f2c313b..ffea722 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,16 @@ -use cgmath::{vec2, vec3, Vector2, Vector3, Zero}; +use cgmath::{vec2, vec3, Vector3}; use image::ImageBuffer; use utilities::prelude::*; -use std::f32::{MAX, MIN}; - mod aabb; +mod acceleration_data; mod camera; +mod intersection; mod ray; mod triangle; -use aabb::AABB; +use acceleration_data::AccelerationData; use camera::Camera; use ray::Ray; use triangle::{Triangle, Vertex}; @@ -72,12 +72,12 @@ fn f_to_u(color: f32) -> u8 { fn debug_raytracer_camera(dim_x: u32, dim_y: u32, camera: &Camera, data: &[Triangle]) { let mut imgbuf = ImageBuffer::new(dim_x, dim_y); - let acceleration_data = create_acceleration_data(data, 8); + let acceleration_data = AccelerationData::create_tree(data, 8); for (x, y, pixel) in imgbuf.enumerate_pixels_mut() { let ray = camera.primary_ray(x, dim_y - y, dim_x, dim_y); - let color = pixel_color(&ray, data, &acceleration_data); + let color = pixel_color(&ray, &acceleration_data); *pixel = image::Rgb([f_to_u(color.x), f_to_u(color.y), f_to_u(color.z)]); } @@ -85,57 +85,10 @@ fn debug_raytracer_camera(dim_x: u32, dim_y: u32, camera: &Camera, data: &[Trian imgbuf.save("raytrace.png").unwrap(); } -fn create_acceleration_data(input_data: &[Triangle], triangles_per_as: u32) -> Vec { - let mut acceleration_data = Vec::new(); - - let accel_count = (input_data.len() as f32 / triangles_per_as as f32).ceil() as usize; - - for i in 0..accel_count { - let mut accel = AABB::new(); - - let mut bbmin = vec3(MAX, MAX, MAX); - let mut bbmax = vec3(MIN, MIN, MIN); - - // 3 vertices per triangles - // 8 triangles per acceleration structure - let start_index = triangles_per_as as usize * i; - let mut end_index = triangles_per_as as usize * (i + 1); - - // check if end_index exceeds input data length - if end_index > input_data.len() { - end_index = input_data.len(); - } - - // set index information - accel.start_index = start_index; - accel.end_index = end_index; - - // create bounding box - for k in start_index..end_index { - for vertex in input_data[k].vertices.iter() { - // check minimum values - bbmin.x = bbmin.x.min(vertex.position.x); - bbmin.y = bbmin.y.min(vertex.position.y); - bbmin.z = bbmin.z.min(vertex.position.z); - - // check maximum values - bbmax.x = bbmax.x.max(vertex.position.x); - bbmax.y = bbmax.y.max(vertex.position.y); - bbmax.z = bbmax.z.max(vertex.position.z); - } - } - - accel.bounds[0] = bbmin; - accel.bounds[1] = bbmax; - - acceleration_data.push(accel); - } - - acceleration_data -} - -fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: &Vec) -> Vector3 { +fn pixel_color(ray: &Ray, acceleration_data: &AccelerationData) -> Vector3 { let mut final_color = vec3(0.0, 1.0, 0.0); + + /* let mut closest_value = MAX; let mut closest_index = -1; let mut barycentric = Vector2::zero(); @@ -156,19 +109,20 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: &Vec) -> V } } } + */ - if closest_index != -1 { - let i = closest_index; - - let triangle = &data[i as usize]; + if let Some(intersection) = acceleration_data.find_closest_hit(ray) { + let triangle = intersection.triangle; + /* let wuv = vec3( - 1.0 - barycentric.x - barycentric.y, - barycentric.x, - barycentric.y, + 1.0 - intersection.barycentric.x - intersection.barycentric.y, + intersection.barycentric.x, + intersection.barycentric.y, ); let st = point_st(&triangle, &wuv); + */ final_color = triangle.color; } @@ -176,8 +130,10 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: &Vec) -> V return final_color; } +/* fn point_st(triangle: &Triangle, wuv: &Vector3) -> Vector2 { return wuv.x * triangle.vertices[0].texture_coordinate + wuv.y * triangle.vertices[1].texture_coordinate + wuv.z * triangle.vertices[2].texture_coordinate; } +*/ diff --git a/src/triangle.rs b/src/triangle.rs index b3bf7ff..33118bb 100644 --- a/src/triangle.rs +++ b/src/triangle.rs @@ -1,7 +1,8 @@ -use cgmath::{InnerSpace, Vector2, Vector3}; +use cgmath::{InnerSpace, Vector2, Vector3, Zero}; use super::ray::Ray; +#[derive(Clone, Copy)] pub struct Vertex { pub position: Vector3, pub texture_coordinate: Vector2, @@ -14,6 +15,13 @@ impl Vertex { texture_coordinate, } } + + pub fn zero() -> Vertex { + Vertex { + position: Vector3::zero(), + texture_coordinate: Vector2::zero(), + } + } } pub struct Triangle { @@ -29,6 +37,13 @@ impl Triangle { } } + pub fn zero() -> Triangle { + Triangle { + vertices: [Vertex::zero(); 3], + color: Vector3::zero(), + } + } + // source: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection pub fn intersect_mt(&self, ray: &Ray, t: &mut f32, barycentric: &mut Vector2) -> bool { let v0v1 = self.vertices[1].position - self.vertices[0].position;