From 5fe2e4a4e681c14a75fe9440a99078944cc373d0 Mon Sep 17 00:00:00 2001 From: STP Date: Mon, 4 Dec 2023 03:49:20 -0500 Subject: [PATCH] Sick ass cornel box --- rhai/scene.rhai | 170 +++++++++++++++++++++++++++++++++++++++--------- src/gui.rs | 9 +++ src/main.rs | 17 ++++- src/material.rs | 4 +- src/node.rs | 24 ++++--- src/ray.rs | 41 ++++++++---- src/state.rs | 10 +-- 7 files changed, 209 insertions(+), 66 deletions(-) diff --git a/rhai/scene.rhai b/rhai/scene.rhai index 5f63b46..b3b236e 100644 --- a/rhai/scene.rhai +++ b/rhai/scene.rhai @@ -1,6 +1,6 @@ let scene = Scene(); -let distance = 10.0; +let distance = 0.99; let camera = Camera( P(0.0,0.0,distance), P(0.0,0.0,0.0), V(0.0,1.0,0.0)); scene.addCamera("+Z Cam", camera); // let camera = Camera( P(0.0,distance,0.1), P(0.0,0.0,0.0), V(0.0,1.0,0.0)); @@ -14,55 +14,161 @@ scene.addCamera("+Z Cam", camera); // let camera = Camera( P(-distance,0.0,0.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0)); // scene.addCamera("-X Cam", camera); -let material = Material(V(0.2,0.9,0.8), V(0.3, 0.8, 0.8), 10.0); -scene.addMaterial("mat1", material); -let material2 = Material(V(0.2,0.9,0.8), V(0.3, 0.8, 0.8), 25.0); -scene.addMaterial("mat2", material); +let falloff = V(0.1, 0.1, 0.15); - -let light = Light(P(0.0,7.0,0.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001)); +let colour = V(0.0,0.5,0.5); +let pos = P(-0.5,0.9,0.5); +let light = Light(pos, colour, falloff); light.active(true); scene.addLight("blue", light); -// let light = Light( P(2.0,7.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001)); -// light.active(false); -// scene.addLight("green", light); +let colour = V(0.0,1.0,0.0); +let pos = P(-0.5,0.9,-0.5); +let light = Light(pos, colour, falloff); +light.active(false); +scene.addLight("green", light); -// let light = Light( P(2.0,7.0,2.0), V(1.0,0.5,0.5), V(0.0, 0.00, 0.001)); -// light.active(false); -// scene.addLight("red", light); +let colour = V(1.0,0.0,0.0); +let light = Light(pos, colour, falloff); +light.active(true); +scene.addLight("red", light); -// let light = Ambient(V(0.5,0.5,0.5)); -// light.active(false); -// scene.addLight("ambient", light); +let colour = V(0.7,0.7,0.7); +let pos = P(0.0,0.9,0.0); +let light = Light(pos, colour, falloff); +light.active(true); +scene.addLight("white", light); - -//let sphere = Sphere(P(0.0,-10.0,0.0), 10.0 ); -//let sphere_node = Node( sphere, material); -//scene.addNode("sphere",sphere_node); +let light = Ambient(V(0.1,0.1,0.1)); +light.active(true); +scene.addLight("ambient", light); //let mesh = Mesh("obj/cow.obj" ); //let mesh_node = Node(mesh); //scene.addNode("mesh", mesh_node); - // let child = sphere_node.child(sphere); // child.translate(V(1.0,1.0,1.0)); //scene.addNode(child); -let sphere2= SphereUnit(); -let sphere2_node = Node( sphere2, material2); +//let sphere2= SphereUnit(); +//let sphere2_node = Node( sphere2, material2); // sphere2_node.rotate(0.1,0.1,0.0); // sphere2_node.translate(0.0,1.0,0.0); -scene.addNode("sphere", sphere2_node); +//scene.addNode("sphere2", sphere2_node); -//let gnonom = Gnonom(); -//let gnonom_node = Node(gnonom, material); -//scene.addNode("gnonom", gnonom_node); +let kd = V(1.0, 1.0, 1.0); // Diffuse color (white) +let ks = V(0.0,0.0,0.0); // Specular color (no specular reflection) +let kr = V(0.0,0.0,0.0); // Reflection color (no reflection) +let white_wall = Material(kd, ks, kr, 10.0); +scene.addMaterial("white_wall", white_wall); -//let cylinder = Cylinder(2.0,1.0 ); -//let cylinder_node = Node(cylinder); -//cylinder_node.scale(1.0,1.0,1.0); -//scene.addNode("cylinder",cylinder_node); +let kd = V(1.0, 0.0, 0.0); // Diffuse color (white) +let ks = V(0.0,0.0,0.0); // Specular color (no specular reflection) +let kr = V(0.0,0.0,0.0); // Reflection color (no reflection) +let red_wall = Material(kd, ks, kr, 10.0); +scene.addMaterial("red_wall", red_wall); -scene \ No newline at end of file +let kd = V(0.0, 1.0, 0.0); // Diffuse color (white) +let ks = V(0.0,0.0,0.0); // Specular color (no specular reflection) +let kr = V(0.0,0.0,0.0); // Reflection color (no reflection) +let green_wall = Material(kd, ks, kr, 10.0); +scene.addMaterial("green_wall", green_wall); + +let kd = V(0.0, 0.0, 1.0); // Diffuse color (white) +let ks = V(0.0,0.0,0.0); // Specular color (no specular reflection) +let kr = V(0.0,0.0,0.0); // Reflection color (no reflection) +let blue_wall = Material(kd, ks, kr, 10.0); +scene.addMaterial("blue_wall", blue_wall); + + +//Rear wall +let rectangle1 = RectangleUnit(); +let rectangle_node1 = Node(rectangle1, white_wall); +rectangle_node1.rotate(0.0, 0.0, 0.0); +rectangle_node1.translate(0.0, 0.0, -1.0); +rectangle_node1.active(true); +scene.addNode("rectangle1", rectangle_node1); + +//Behind wall +let rectangle6 = RectangleUnit(); +let rectangle_node6 = Node(rectangle6, white_wall); +rectangle_node6.rotate(0.0, 180.0, 0.0); +rectangle_node6.translate(0.0, 0.0, 1.0); +rectangle_node6.active(true); +scene.addNode("rectangle6", rectangle_node6); + +//Right wall +let rectangle2 = RectangleUnit(); +let rectangle_node2 = Node(rectangle2, green_wall); +rectangle_node2.rotate(0.0, -90.0, 0.0); +rectangle_node2.translate(1.0, 0.0, 0.0); +rectangle_node2.active(true); +scene.addNode("rectangle2", rectangle_node2); + +//Floor +let rectangle3 = RectangleUnit(); +let rectangle_node3 = Node(rectangle3, red_wall); +rectangle_node3.rotate(0.0, 90.0, 0.0); +rectangle_node3.translate(-1.0, 0.0, 0.0); +rectangle_node3.active(true); +scene.addNode("rectangle3", rectangle_node3); + +//Left wall +let rectangle4 = RectangleUnit(); +let rectangle_node4 = Node(rectangle4, white_wall); +rectangle_node4.rotate(90.0, 0.0, 0.0); +rectangle_node4.translate(0.0, 1.0, 0.0); +rectangle_node4.active(true); +scene.addNode("rectangle4", rectangle_node4); + +//Ceiling +let rectangle5 = RectangleUnit(); +let rectangle_node5 = Node(rectangle5, white_wall); +rectangle_node5.rotate(-90.0, 0.0, 0.0); + +rectangle_node5.translate(0.0, -1.0, 0.0); +rectangle_node5.active(true); +scene.addNode("rectangle5", rectangle_node5); + + +let kd = V(0.0, 0.0, 0.0); // Diffuse color (white) +let ks = V(0.0,0.0,0.0); // Specular color (no specular reflection) +let kr = V(1.0,1.0,1.0); // Reflection color (no reflection) +let reflective = Material(kd, ks, kr, 10.0); +scene.addMaterial("reflective", reflective); + +let sphere = Sphere(P(0.0,0.0,0.0), 0.4 ); +let sphere_node = Node( sphere, reflective); +sphere_node.translate(0.4, -0.6, 0.0); +scene.addNode("sphere",sphere_node); + +let kd = V(0.3, 0.3, 0.3); // Diffuse color (white) +let ks = V(0.3,0.3,0.0); // Specular color (no specular reflection) +let kr = V(0.0,0.0,1.0); // Reflection color (no reflection) +let shiny = Material(kd, ks, kr, 2.0); +scene.addMaterial("shiny", shiny); + +let cube = CubeUnit(); +let cube_node = Node( cube, shiny); +cube_node.translate(-0.5,-0.6,0.0); +cube_node.scale(0.3,0.2,0.2); +cube_node.rotate(0.0,45.0,30.0); +scene.addNode("cube",cube_node); + +let gnonom = Gnonom(); +let gnonom_node = Node(gnonom, shiny); +gnonom_node.scale(0.2,0.2,0.2); +gnonom_node.translate(0.0, 0.-0.7, 0.8); +gnonom_node.rotate(0.0, 45.0, 0.0); +gnonom_node.active(false); +scene.addNode("gnonom", gnonom_node); + +// let cylinder = Cylinder(2.0, 1.0); +// let cylinder_node = Node(cylinder, material); +// cylinder_node.scale(1.0, 1.0, 1.0); +// scene.addNode("cylinder", cylinder_node); + +//let cone + +scene diff --git a/src/gui.rs b/src/gui.rs index 5baec7a..4c00d2a 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -28,6 +28,8 @@ const MIN_SAMPLES: u32 = 1; const MAX_SAMPLES: u32 = 10; const MIN_RANDOM: f64 = 100.0; const MAX_RANDOM: f64 = 1000.0; +const MIN_EPSILON: f64 = 1e-11; +const MAX_EPSILON: f64 = 1.0; //DIFFUSE CONSTANTS const MIN_DIFFUSE_RAYS: u8 = 1; @@ -240,6 +242,13 @@ impl Gui { MAX_DEPTH, &mut self.raytracing_option.ray_depth, ); + //Epsilon slider + ui.slider( + "Epsilon", + MIN_EPSILON, + MAX_EPSILON, + &mut self.raytracing_option.epsilon, + ); //Ray samples slider ui.slider( "Ray Samples", diff --git a/src/main.rs b/src/main.rs index 032a19c..14d3f1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ use crate::state::run; use error_iter::ErrorIter; -const EPSILON: f64 = 1e-8; +const EPSILON: f64 = 1e-7; const INFINITY: f64 = 1e10; use log::error; +//use nalgebra::{Matrix4, RowVector4, Vector3, Vector4}; use std::env; use std::error::Error; @@ -23,6 +24,20 @@ fn main() { env_logger::init(); env::set_var("RUST_BACKTRACE", "1"); //let args: Vec = env::args().collect(); + + // let vec = Vector3::new(1.0, 1.0, 1.0); + // let translation = Vector3::new(1.0, 1.0, 1.0); + // let translation_matrix = Matrix4::new_translation(&translation); + // println!( + // "{}, {}", + // translation_matrix, + // translation_matrix.transform_vector(&vec) + // ); + // let mut translation_matrix = translation_matrix.transpose(); + // translation_matrix.set_row(3, &RowVector4::new(0.0, 0.0, 0.0, 0.0)); + // println!( + // "{}, {}", // translation_matrix, // translation_matrix.transform_vector(&vec) + // ); if let Err(e) = run() { println!("Error at runtime: {}", e); }; diff --git a/src/material.rs b/src/material.rs index 7e33021..f9b0f24 100644 --- a/src/material.rs +++ b/src/material.rs @@ -10,10 +10,10 @@ pub struct Material { } impl Material { - pub fn new(kd: Vector3, ks: Vector3, shininess: f64) -> Material { + pub fn new(kd: Vector3, ks: Vector3, kr: Vector3, shininess: f64) -> Material { let kd = kd.cast(); let ks = ks.cast(); - let kr = ks.cast(); + let kr = kr.cast(); let shininess = shininess as f32; Material { kd, diff --git a/src/node.rs b/src/node.rs index 6e760b9..1dd7791 100644 --- a/src/node.rs +++ b/src/node.rs @@ -5,7 +5,7 @@ use crate::{ ray::{Intersection, Ray}, EPSILON, }; -use nalgebra::{Matrix4, Vector3}; +use nalgebra::{distance, Matrix3, Matrix4, Vector3}; use std::sync::Arc; #[derive(Clone)] @@ -21,6 +21,7 @@ pub struct Node { //Model matricies pub model: Matrix4, pub inv_model: Matrix4, + pub inv_transpose_model: Matrix3, //If the node is active pub active: bool, } @@ -38,7 +39,7 @@ impl Node { translation: [0.0, 0.0, 0.0], model: Matrix4::identity(), inv_model: Matrix4::identity(), - + inv_transpose_model: Matrix3::identity(), active: true, } } @@ -55,12 +56,6 @@ impl Node { //Rotate a mesh by adding to its rotation pub fn rotate(&mut self, roll: f64, pitch: f64, yaw: f64) { - //Convert to radians - let roll = roll.to_radians(); - // Convert pitch and yaw to radians - let pitch = pitch.to_radians(); - let yaw = yaw.to_radians(); - // Add the roll, pitch, and yaw to the current rotation self.rotation[0] += roll; self.rotation[1] += pitch; @@ -80,9 +75,9 @@ impl Node { } // Scale a mesh by adding to its current scale pub fn scale(&mut self, x: f64, y: f64, z: f64) { - self.scale[0] += x; - self.scale[1] += y; - self.scale[2] += z; + self.scale[0] = x; + self.scale[1] = y; + self.scale[2] = z; // Recompute the model and inverse model matrices self.compute(); @@ -97,11 +92,13 @@ impl Node { let scale_matrix = Matrix4::new_nonuniform_scaling(&scale); // Rotation matrix let (roll, pitch, yaw) = (self.rotation[0], self.rotation[1], self.rotation[2]); - let rotation_matrix = Matrix4::from_euler_angles(roll, pitch, yaw); + let rotation_matrix = + Matrix4::from_euler_angles(roll.to_radians(), pitch.to_radians(), yaw.to_radians()); // Compute the model matrix by combining the translation, rotation, and scale matrices self.model = (translation_matrix * rotation_matrix * scale_matrix).cast(); // Compute the inverse model matrix by inverting the model matrix self.inv_model = self.model.try_inverse().unwrap(); + self.inv_transpose_model = self.inv_model.transpose().remove_row(3).remove_column(3); self.aabb.transform_mut(&self.model); } // Intersection of a ray, will convert to model coords and check @@ -111,7 +108,8 @@ impl Node { if intersect.distance < EPSILON { return None; } - intersect.transform_mut(&self.model, &self.inv_model); //Transform to world coords + intersect.transform_mut(&self.model, &self.inv_transpose_model); //Transform to world coords + intersect.distance = distance(&intersect.point, &ray.a); return Some(intersect); } return None; diff --git a/src/ray.rs b/src/ray.rs index 578423f..0de6d4f 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -1,5 +1,5 @@ -use crate::{bvh::BVH, node::Node, scene::Scene, state::RaytracingOption, EPSILON}; -use nalgebra::{distance, Matrix4, Point3, Vector3}; +use crate::{bvh::BVH, light::Light, node::Node, scene::Scene, state::RaytracingOption, EPSILON}; +use nalgebra::{distance, Matrix3, Matrix4, Point3, Vector3}; use rand; fn random_vec() -> Vector3 { @@ -18,9 +18,16 @@ pub struct Intersection { } //Intersection point including point and normal impl Intersection { - pub fn transform_mut(&mut self, trans: &Matrix4, inv_trans: &Matrix4) { + pub fn transform(&mut self, trans: &Matrix4, inv_trans: &Matrix4) -> Intersection { + Intersection { + point: trans.transform_point(&self.point), + normal: inv_trans.transpose().transform_vector(&self.normal), + distance: self.distance, + } + } + pub fn transform_mut(&mut self, trans: &Matrix4, inv_transpose: &Matrix3) { self.point = trans.transform_point(&self.point); - self.normal = inv_trans.transpose().transform_vector(&self.normal); + self.normal = inv_transpose * self.normal; } } @@ -94,10 +101,6 @@ impl Ray { if node.aabb.intersect_ray(&ray) { //Check node intersection if let Some(intersect) = node.intersect_ray(&ray) { - // Dont intersect with own primitive - if intersect.distance < EPSILON { - continue; - } // Check for closest distance by converting to world coords let distance = distance(&ray_a, &intersect.point); if distance < closest_distance { @@ -182,7 +185,7 @@ impl Ray { //Niave Shadows if options.shadows { let to_light_ray = Ray::new(*point, to_light); - if to_light_ray.light_blocked(scene, node, bvh) { + if to_light_ray.light_blocked(scene, light, bvh) { continue; } } @@ -238,7 +241,8 @@ impl Ray { colour } - pub fn light_blocked(&self, scene: &Scene, _node: &Node, bvh: &Option) -> bool { + pub fn light_blocked(&self, scene: &Scene, light: &Light, bvh: &Option) -> bool { + let light_distance = distance(&self.a, &light.position); match bvh { Some(bvh) => { //We have a bvh so use bvh traversal @@ -247,7 +251,11 @@ impl Ray { continue; } match bvh.traverse(self, 0) { - Some(_) => return true, + Some((_, intersect)) => { + if intersect.distance < light_distance + EPSILON { + return true; + } + } None => continue, } } @@ -259,14 +267,19 @@ impl Ray { continue; } if node.aabb.intersect_ray(self) { - if node.intersect_ray(self).is_some() { - return true; + match node.intersect_ray(self) { + Some(intersect) => { + if intersect.distance < light_distance { + return true; + } + } + None => continue, } } } - return false; } } + return false; } //Cast a set of rays pub fn cast_rays( diff --git a/src/state.rs b/src/state.rs index 06e2094..6041fe0 100644 --- a/src/state.rs +++ b/src/state.rs @@ -37,6 +37,7 @@ pub struct RaytracingOption { pub pixel_clear: [u8; 4], pub pixels_per_thread: u32, pub buffer_proportion: f32, + pub epsilon: f64, pub buffer_fov: f64, pub ray_depth: u8, pub diffuse_rays: u8, @@ -56,18 +57,19 @@ impl RaytracingOption { ray_randomness: 100.0, clear_color: [0x22, 0x00, 0x11, 0x55], pixel_clear: [0x55, 0x00, 0x22, 0x55], - pixels_per_thread: 200, - buffer_proportion: 1.0, - buffer_fov: 110.0, + pixels_per_thread: 1000, + buffer_proportion: 0.1, + buffer_fov: 70.0, ray_depth: 5, diffuse_rays: 3, - diffuse_coefficient: 0.8, + diffuse_coefficient: 0.1, bvh_active: false, shadows: true, diffuse: true, reflect: true, specular: true, falloff: true, + epsilon: 1e-6, } } }