Start implementing AABB tree

This commit is contained in:
hodasemi 2019-04-15 14:53:27 +02:00
parent d732ff8a0f
commit ad28987134
7 changed files with 241 additions and 126 deletions

View file

@ -1,11 +1,10 @@
[package] [package]
name = "rust_opengl" name = "rustray"
edition = "2018" edition = "2018"
version = "0.1.0" version = "0.1.0"
authors = ["hodasemi <michaelh.95@t-online.de>"] authors = ["hodasemi <michaelh.95@t-online.de>"]
[dependencies] [dependencies]
sdl2 = "0.30"
cgmath = "*" cgmath = "*"
utilities = { path = "../../Gavania/utilities" } utilities = { git = "https://gitlab.com/hodasemi/utilities.git" }
image = "*" image = "*"

View file

@ -2,18 +2,23 @@ use cgmath::{Vector3, Zero};
use super::ray::Ray; use super::ray::Ray;
#[derive(Clone, Copy, Debug)]
pub struct AABB { pub struct AABB {
pub bounds: [Vector3<f32>; 2], pub bounds: [Vector3<f32>; 2],
pub start_index: usize, pub start_index: isize,
pub end_index: usize, pub end_index: isize,
pub left_child: isize,
pub right_child: isize,
} }
impl AABB { impl AABB {
pub fn new() -> AABB { pub fn new() -> AABB {
AABB { AABB {
bounds: [Vector3::zero(), Vector3::zero()], bounds: [Vector3::zero(), Vector3::zero()],
start_index: 0, start_index: -1,
end_index: 0, end_index: -1,
left_child: -1,
right_child: -1,
} }
} }

165
src/acceleration_data.rs Normal file
View file

@ -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<Intersection> {
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<AABB> {
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<f32>, v1: Vector3<f32>) -> Vector3<f32> {
Vector3::new(v0.x.min(v1.x), v0.y.min(v1.y), v0.z.min(v1.z))
}
fn max(v0: Vector3<f32>, v1: Vector3<f32>) -> Vector3<f32> {
Vector3::new(v0.x.max(v1.x), v0.y.max(v1.y), v0.z.max(v1.z))
}
}

View file

@ -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);
}

29
src/intersection.rs Normal file
View file

@ -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<f32>,
}
impl Intersection {
pub fn new(distance: f32, triangle: Triangle, barycentric: Vector2<f32>) -> Intersection {
Intersection {
distance,
triangle,
barycentric,
}
}
pub fn zero() -> Intersection {
Intersection {
distance: MAX,
triangle: Triangle::zero(),
barycentric: Vector2::zero(),
}
}
}

View file

@ -1,16 +1,16 @@
use cgmath::{vec2, vec3, Vector2, Vector3, Zero}; use cgmath::{vec2, vec3, Vector3};
use image::ImageBuffer; use image::ImageBuffer;
use utilities::prelude::*; use utilities::prelude::*;
use std::f32::{MAX, MIN};
mod aabb; mod aabb;
mod acceleration_data;
mod camera; mod camera;
mod intersection;
mod ray; mod ray;
mod triangle; mod triangle;
use aabb::AABB; use acceleration_data::AccelerationData;
use camera::Camera; use camera::Camera;
use ray::Ray; use ray::Ray;
use triangle::{Triangle, Vertex}; 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]) { fn debug_raytracer_camera(dim_x: u32, dim_y: u32, camera: &Camera, data: &[Triangle]) {
let mut imgbuf = ImageBuffer::new(dim_x, dim_y); 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() { for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
let ray = camera.primary_ray(x, dim_y - y, dim_x, dim_y); 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)]); *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(); imgbuf.save("raytrace.png").unwrap();
} }
fn create_acceleration_data(input_data: &[Triangle], triangles_per_as: u32) -> Vec<AABB> { fn pixel_color(ray: &Ray, acceleration_data: &AccelerationData) -> Vector3<f32> {
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<AABB>) -> Vector3<f32> {
let mut final_color = vec3(0.0, 1.0, 0.0); let mut final_color = vec3(0.0, 1.0, 0.0);
/*
let mut closest_value = MAX; let mut closest_value = MAX;
let mut closest_index = -1; let mut closest_index = -1;
let mut barycentric = Vector2::zero(); let mut barycentric = Vector2::zero();
@ -156,19 +109,20 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: &Vec<AABB>) -> V
} }
} }
} }
*/
if closest_index != -1 { if let Some(intersection) = acceleration_data.find_closest_hit(ray) {
let i = closest_index; let triangle = intersection.triangle;
let triangle = &data[i as usize];
/*
let wuv = vec3( let wuv = vec3(
1.0 - barycentric.x - barycentric.y, 1.0 - intersection.barycentric.x - intersection.barycentric.y,
barycentric.x, intersection.barycentric.x,
barycentric.y, intersection.barycentric.y,
); );
let st = point_st(&triangle, &wuv); let st = point_st(&triangle, &wuv);
*/
final_color = triangle.color; final_color = triangle.color;
} }
@ -176,8 +130,10 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: &Vec<AABB>) -> V
return final_color; return final_color;
} }
/*
fn point_st(triangle: &Triangle, wuv: &Vector3<f32>) -> Vector2<f32> { fn point_st(triangle: &Triangle, wuv: &Vector3<f32>) -> Vector2<f32> {
return wuv.x * triangle.vertices[0].texture_coordinate return wuv.x * triangle.vertices[0].texture_coordinate
+ wuv.y * triangle.vertices[1].texture_coordinate + wuv.y * triangle.vertices[1].texture_coordinate
+ wuv.z * triangle.vertices[2].texture_coordinate; + wuv.z * triangle.vertices[2].texture_coordinate;
} }
*/

View file

@ -1,7 +1,8 @@
use cgmath::{InnerSpace, Vector2, Vector3}; use cgmath::{InnerSpace, Vector2, Vector3, Zero};
use super::ray::Ray; use super::ray::Ray;
#[derive(Clone, Copy)]
pub struct Vertex { pub struct Vertex {
pub position: Vector3<f32>, pub position: Vector3<f32>,
pub texture_coordinate: Vector2<f32>, pub texture_coordinate: Vector2<f32>,
@ -14,6 +15,13 @@ impl Vertex {
texture_coordinate, texture_coordinate,
} }
} }
pub fn zero() -> Vertex {
Vertex {
position: Vector3::zero(),
texture_coordinate: Vector2::zero(),
}
}
} }
pub struct Triangle { 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 // 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<f32>) -> bool { pub fn intersect_mt(&self, ray: &Ray, t: &mut f32, barycentric: &mut Vector2<f32>) -> bool {
let v0v1 = self.vertices[1].position - self.vertices[0].position; let v0v1 = self.vertices[1].position - self.vertices[0].position;