Move tracer objects into modules
This commit is contained in:
parent
44715eea21
commit
99ad9ea260
5 changed files with 232 additions and 153 deletions
65
src/aabb.rs
Normal file
65
src/aabb.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use cgmath::{Vector3, Zero};
|
||||
|
||||
use super::ray::Ray;
|
||||
|
||||
pub struct AABB {
|
||||
pub bounds: [Vector3<f32>; 2],
|
||||
pub start_index: usize,
|
||||
pub end_index: usize,
|
||||
}
|
||||
|
||||
impl AABB {
|
||||
pub fn new() -> AABB {
|
||||
AABB {
|
||||
bounds: [Vector3::zero(), Vector3::zero()],
|
||||
start_index: 0,
|
||||
end_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersect(&self, ray: &Ray) -> bool {
|
||||
let mut tmin = (self.bounds[ray.signs.x].x - ray.origin.x) * ray.inv_direction.x;
|
||||
let mut tmax = (self.bounds[1 - ray.signs.x].x - ray.origin.x) * ray.inv_direction.x;
|
||||
let tymin = (self.bounds[ray.signs.y].y - ray.origin.y) * ray.inv_direction.y;
|
||||
let tymax = (self.bounds[1 - ray.signs.y].y - ray.origin.y) * ray.inv_direction.y;
|
||||
|
||||
if tmin > tymax || tymin > tmax {
|
||||
return false;
|
||||
}
|
||||
|
||||
if tymin > tmin {
|
||||
tmin = tymin;
|
||||
}
|
||||
|
||||
if tymax < tmax {
|
||||
tmax = tymax;
|
||||
}
|
||||
|
||||
let tzmin = (self.bounds[ray.signs.z].z - ray.origin.z) * ray.inv_direction.z;
|
||||
let tzmax = (self.bounds[1 - ray.signs.z].z - ray.origin.z) * ray.inv_direction.z;
|
||||
|
||||
if tmin > tzmax || tzmin > tmax {
|
||||
return false;
|
||||
}
|
||||
|
||||
if tzmin > tmin {
|
||||
tmin = tzmin;
|
||||
}
|
||||
|
||||
if tzmax < tmax {
|
||||
tmax = tzmax;
|
||||
}
|
||||
|
||||
let mut t = tmin;
|
||||
|
||||
if t < 0.0 {
|
||||
t = tmax;
|
||||
|
||||
if t < 0.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
203
src/main.rs
203
src/main.rs
|
@ -1,115 +1,21 @@
|
|||
use cgmath::prelude::*;
|
||||
|
||||
use cgmath::{vec3, vec4, InnerSpace, Matrix4, Point3, Vector3, Zero};
|
||||
use cgmath::{vec3, Vector3};
|
||||
|
||||
use image::ImageBuffer;
|
||||
use utilities::prelude::*;
|
||||
|
||||
use std::f32::{consts::PI as M_PI, MAX, MIN};
|
||||
use std::f32::{MAX, MIN};
|
||||
|
||||
struct Triangle {
|
||||
points: [Vector3<f32>; 3],
|
||||
}
|
||||
mod triangle;
|
||||
use triangle::Triangle;
|
||||
|
||||
impl Triangle {
|
||||
pub fn new(v0: Vector3<f32>, v1: Vector3<f32>, v2: Vector3<f32>) -> Triangle {
|
||||
Triangle {
|
||||
points: [v0, v1, v2],
|
||||
}
|
||||
}
|
||||
}
|
||||
mod aabb;
|
||||
use aabb::AABB;
|
||||
|
||||
struct View {
|
||||
position: Vector3<f32>,
|
||||
look_at: Vector3<f32>,
|
||||
fov: f32,
|
||||
}
|
||||
mod ray;
|
||||
use ray::Ray;
|
||||
|
||||
struct Ray {
|
||||
origin: Vector3<f32>,
|
||||
direction: Vector3<f32>,
|
||||
inv_direction: Vector3<f32>,
|
||||
signs: Vector3<usize>,
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(origin: Vector3<f32>, direction: Vector3<f32>) -> Ray {
|
||||
let inv_direction = 1.0 / direction;
|
||||
|
||||
let x = (inv_direction.x < 0.0) as usize;
|
||||
let y = (inv_direction.y < 0.0) as usize;
|
||||
let z = (inv_direction.z < 0.0) as usize;
|
||||
|
||||
Ray {
|
||||
origin,
|
||||
direction,
|
||||
inv_direction,
|
||||
signs: Vector3::new(x, y, z),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AABB {
|
||||
bounds: [Vector3<f32>; 2],
|
||||
start_index: usize,
|
||||
end_index: usize,
|
||||
}
|
||||
|
||||
impl AABB {
|
||||
fn new() -> AABB {
|
||||
AABB {
|
||||
bounds: [Vector3::zero(), Vector3::zero()],
|
||||
start_index: 0,
|
||||
end_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn intersect(&self, ray: &Ray) -> bool {
|
||||
let mut tmin = (self.bounds[ray.signs.x].x - ray.origin.x) * ray.inv_direction.x;
|
||||
let mut tmax = (self.bounds[1 - ray.signs.x].x - ray.origin.x) * ray.inv_direction.x;
|
||||
let tymin = (self.bounds[ray.signs.y].y - ray.origin.y) * ray.inv_direction.y;
|
||||
let tymax = (self.bounds[1 - ray.signs.y].y - ray.origin.y) * ray.inv_direction.y;
|
||||
|
||||
if tmin > tymax || tymin > tmax {
|
||||
return false;
|
||||
}
|
||||
|
||||
if tymin > tmin {
|
||||
tmin = tymin;
|
||||
}
|
||||
|
||||
if tymax < tmax {
|
||||
tmax = tymax;
|
||||
}
|
||||
|
||||
let tzmin = (self.bounds[ray.signs.z].z - ray.origin.z) * ray.inv_direction.z;
|
||||
let tzmax = (self.bounds[1 - ray.signs.z].z - ray.origin.z) * ray.inv_direction.z;
|
||||
|
||||
if tmin > tzmax || tzmin > tmax {
|
||||
return false;
|
||||
}
|
||||
|
||||
if tzmin > tmin {
|
||||
tmin = tzmin;
|
||||
}
|
||||
|
||||
if tzmax < tmax {
|
||||
tmax = tzmax;
|
||||
}
|
||||
|
||||
let mut t = tmin;
|
||||
|
||||
if t < 0.0 {
|
||||
t = tmax;
|
||||
|
||||
if t < 0.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
mod view;
|
||||
use view::View;
|
||||
|
||||
fn main() {
|
||||
let input_data = [Triangle::new(
|
||||
|
@ -121,6 +27,7 @@ fn main() {
|
|||
let view = View {
|
||||
position: vec3(0.0, -4.0, 4.0),
|
||||
look_at: vec3(0.0, 0.0, 0.0),
|
||||
up: vec3(0.0, 0.0, 1.0),
|
||||
fov: 45.0,
|
||||
};
|
||||
|
||||
|
@ -131,33 +38,65 @@ fn f_to_u(color: f32) -> u8 {
|
|||
((color * 255.0) / 1.0) as u8
|
||||
}
|
||||
|
||||
/*
|
||||
fn calculate_ray(x: u32, y: u32, dim_x: u32, dim_y: u32, view: &View) -> Ray {
|
||||
let aspect_ratio = dim_x as f32 / dim_y as f32;
|
||||
|
||||
let fov = view.fov / 180.0 * M_PI * 2.0;
|
||||
let fov = view.fov / M_PI * 2.0 / 180.0;
|
||||
|
||||
let p_x = (1.0 - 2.0 * ((x as f32 + 0.5) / dim_x as f32)) * fov * aspect_ratio;
|
||||
let p_y = (2.0 * (((y) as f32 + 0.5) / dim_y as f32) - 1.0) * fov;
|
||||
|
||||
let camera_to_world = Matrix4::look_at(
|
||||
let look_at = Matrix4::look_at(
|
||||
Point3::from_vec(view.position),
|
||||
Point3::from_vec(view.look_at),
|
||||
vec3(0.0, 0.0, 1.0),
|
||||
)
|
||||
.invert()
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
let test = look_at_test(view.position, view.look_at, vec3(0.0, 0.0, 1.0));
|
||||
|
||||
let camera_to_world = look_at.invert().unwrap();
|
||||
|
||||
let origin = camera_to_world * vec4(0.0, 0.0, 0.0, 1.0);
|
||||
let direction = camera_to_world * vec4(p_x, p_y, -1.0, 1.0);
|
||||
|
||||
Ray::new(origin.truncate(), -direction.truncate().normalize())
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
fn look_at_test(eye: Vector3<f32>, center: Vector3<f32>, up: Vector3<f32>) -> Matrix4<f32> {
|
||||
let mut look_at_matrix = Matrix4::identity();
|
||||
|
||||
let forward = (eye - center).normalize();
|
||||
let right = up.cross(forward).normalize();
|
||||
let up = forward.cross(right);
|
||||
|
||||
look_at_matrix[0][0] = right.x;
|
||||
look_at_matrix[0][1] = right.y;
|
||||
look_at_matrix[0][2] = right.z;
|
||||
|
||||
look_at_matrix[1][0] = up.x;
|
||||
look_at_matrix[1][1] = up.y;
|
||||
look_at_matrix[1][2] = up.z;
|
||||
|
||||
look_at_matrix[2][0] = forward.x;
|
||||
look_at_matrix[2][1] = forward.y;
|
||||
look_at_matrix[2][2] = forward.z;
|
||||
|
||||
look_at_matrix[3][0] = eye.x;
|
||||
look_at_matrix[3][1] = eye.y;
|
||||
look_at_matrix[3][2] = eye.z;
|
||||
|
||||
look_at_matrix
|
||||
}
|
||||
*/
|
||||
|
||||
fn debug_raytracer(dim_x: u32, dim_y: u32, view: &View, data: &[Triangle]) {
|
||||
let mut imgbuf = ImageBuffer::new(dim_x, dim_y);
|
||||
|
||||
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
|
||||
let ray = calculate_ray(x, y, dim_x, dim_y, view);
|
||||
let ray = Ray::primary_ray(x, y, dim_x, dim_y, view);
|
||||
|
||||
let acceleration_data = create_acceleration_data(data);
|
||||
|
||||
|
@ -226,12 +165,9 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: Vec<AABB>) -> Ve
|
|||
for accel in acceleration_data.iter() {
|
||||
if accel.intersect(ray) {
|
||||
for i in accel.start_index..accel.end_index {
|
||||
let v0 = data[i].points[0];
|
||||
let v1 = data[i].points[1];
|
||||
let v2 = data[i].points[2];
|
||||
let mut t = 0.0;
|
||||
|
||||
if ray_triangle_intersect_mt(ray, v0, v1, v2, &mut t) {
|
||||
if data[i].intersect_mt(ray, &mut t) {
|
||||
if t < closest_value {
|
||||
closest_index = i as i32;
|
||||
closest_value = t;
|
||||
|
@ -247,42 +183,3 @@ fn pixel_color(ray: &Ray, data: &[Triangle], acceleration_data: Vec<AABB>) -> Ve
|
|||
|
||||
return final_color;
|
||||
}
|
||||
|
||||
// source: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
|
||||
fn ray_triangle_intersect_mt(
|
||||
ray: &Ray,
|
||||
v0: Vector3<f32>,
|
||||
v1: Vector3<f32>,
|
||||
v2: Vector3<f32>,
|
||||
t: &mut f32,
|
||||
) -> bool {
|
||||
let v0v1 = v1 - v0;
|
||||
let v0v2 = v2 - v0;
|
||||
let pvec = ray.direction.cross(v0v2);
|
||||
let det = v0v1.dot(pvec);
|
||||
|
||||
// ray and triangle are parallel if det is close to 0
|
||||
if det.abs() < 0.001 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inv_det = 1.0 / det;
|
||||
|
||||
let tvec = ray.origin - v0;
|
||||
let u = tvec.dot(pvec) * inv_det;
|
||||
|
||||
if u < 0.0 || u > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let qvec = tvec.cross(v0v1);
|
||||
let v = ray.direction.dot(qvec) * inv_det;
|
||||
|
||||
if v < 0.0 || u + v > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
*t = v0v2.dot(qvec) * inv_det;
|
||||
|
||||
true
|
||||
}
|
||||
|
|
41
src/ray.rs
Normal file
41
src/ray.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use cgmath::{vec2, vec3, InnerSpace, Vector3};
|
||||
|
||||
use super::view::View;
|
||||
|
||||
pub struct Ray {
|
||||
pub origin: Vector3<f32>,
|
||||
pub direction: Vector3<f32>,
|
||||
pub inv_direction: Vector3<f32>,
|
||||
pub signs: Vector3<usize>,
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(origin: Vector3<f32>, direction: Vector3<f32>) -> Ray {
|
||||
let inv_direction = 1.0 / direction;
|
||||
|
||||
let x = (inv_direction.x < 0.0) as usize;
|
||||
let y = (inv_direction.y < 0.0) as usize;
|
||||
let z = (inv_direction.z < 0.0) as usize;
|
||||
|
||||
Ray {
|
||||
origin,
|
||||
direction,
|
||||
inv_direction,
|
||||
signs: Vector3::new(x, y, z),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn primary_ray(x: u32, y: u32, dim_y: u32, dim_x: u32, view: &View) -> Ray {
|
||||
let aspect_ratio = dim_x as f32 / dim_y as f32;
|
||||
|
||||
let uv = vec2(x as f32, y as f32);
|
||||
|
||||
let (up, right) = view.axises();
|
||||
|
||||
let trans = 2.0 * uv - vec2(1.0, 1.0);
|
||||
let mut dir = view.look_at + right * trans.x + up * trans.y;
|
||||
dir = vec3(dir.x * aspect_ratio, dir.y, dir.z * aspect_ratio);
|
||||
|
||||
return Self::new(view.position, dir.normalize());
|
||||
}
|
||||
}
|
48
src/triangle.rs
Normal file
48
src/triangle.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use cgmath::{InnerSpace, Vector3};
|
||||
|
||||
use super::ray::Ray;
|
||||
|
||||
pub struct Triangle {
|
||||
pub points: [Vector3<f32>; 3],
|
||||
}
|
||||
|
||||
impl Triangle {
|
||||
pub fn new(v0: Vector3<f32>, v1: Vector3<f32>, v2: Vector3<f32>) -> Triangle {
|
||||
Triangle {
|
||||
points: [v0, v1, v2],
|
||||
}
|
||||
}
|
||||
|
||||
// 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) -> bool {
|
||||
let v0v1 = self.points[1] - self.points[0];
|
||||
let v0v2 = self.points[2] - self.points[0];
|
||||
let pvec = ray.direction.cross(v0v2);
|
||||
let det = v0v1.dot(pvec);
|
||||
|
||||
// ray and triangle are parallel if det is close to 0
|
||||
if det.abs() < 0.001 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inv_det = 1.0 / det;
|
||||
|
||||
let tvec = ray.origin - self.points[0];
|
||||
let u = tvec.dot(pvec) * inv_det;
|
||||
|
||||
if u < 0.0 || u > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let qvec = tvec.cross(v0v1);
|
||||
let v = ray.direction.dot(qvec) * inv_det;
|
||||
|
||||
if v < 0.0 || u + v > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
*t = v0v2.dot(qvec) * inv_det;
|
||||
|
||||
true
|
||||
}
|
||||
}
|
28
src/view.rs
Normal file
28
src/view.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use cgmath::{InnerSpace, Vector3};
|
||||
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct View {
|
||||
pub position: Vector3<f32>,
|
||||
pub look_at: Vector3<f32>,
|
||||
pub up: Vector3<f32>,
|
||||
pub fov: f32,
|
||||
}
|
||||
|
||||
impl View {
|
||||
/// returns `up` and `right`
|
||||
pub fn axises(&self) -> (Vector3<f32>, Vector3<f32>) {
|
||||
let view_dir = self.look_at - self.position;
|
||||
|
||||
let horiz_axis = view_dir.cross(self.up).normalize();
|
||||
let vert_axis = horiz_axis.cross(view_dir).normalize();
|
||||
let right = horiz_axis * Self::scale(self.fov);
|
||||
let up = vert_axis * Self::scale(-self.fov);
|
||||
|
||||
(up, right)
|
||||
}
|
||||
|
||||
fn scale(fov: f32) -> f32 {
|
||||
(0.5 * fov * PI / 180.0).tan()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue