More gui options!

This commit is contained in:
STP
2023-12-03 22:45:49 -05:00
parent 9276088b4b
commit daed0ef0b9
6 changed files with 197 additions and 198 deletions

View File

@@ -277,6 +277,10 @@ impl Gui {
); );
// Enable BVH // Enable BVH
ui.checkbox("Enable BVH", &mut self.raytracing_option.bvh_active); ui.checkbox("Enable BVH", &mut self.raytracing_option.bvh_active);
ui.checkbox("Enable Shadows", &mut self.raytracing_option.shadows);
ui.checkbox("Enable Reflections", &mut self.raytracing_option.reflect);
ui.checkbox("Enable Specular", &mut self.raytracing_option.specular);
ui.checkbox("Enable Diffuse", &mut self.raytracing_option.diffuse);
// Apply stored changes // Apply stored changes
if ui.button("Apply") { if ui.button("Apply") {
self.event = Some(GuiEvent::RaytracerOption(self.raytracing_option.clone())); self.event = Some(GuiEvent::RaytracerOption(self.raytracing_option.clone()));
@@ -346,9 +350,7 @@ impl Gui {
// SCENE -------------------------------------------- // SCENE --------------------------------------------
if CollapsingHeader::new("Scene").build(ui) { if CollapsingHeader::new("Scene").build(ui) {
if ui.button("Update Scene") { if ui.button("Update Scene") {
for (_, node) in &mut self.scene.nodes { self.scene.compute();
node.compute();
}
self.event = Some(GuiEvent::SceneLoad(self.scene.clone())); self.event = Some(GuiEvent::SceneLoad(self.scene.clone()));
} }
// Edit transformation of nodes // Edit transformation of nodes

View File

@@ -1,23 +1,12 @@
use crate::state::run; use crate::state::run;
use bvh::BVH;
use camera::Camera;
use error_iter::ErrorIter; use error_iter::ErrorIter;
const EPSILON: f64 = 1e-8; const EPSILON: f64 = 1e-8;
const INFINITY: f64 = 1e10; const INFINITY: f64 = 1e10;
use gui::{init_engine};
use log::error; use log::error;
use nalgebra::Vector3;
use rand::random;
use ray::Ray;
use scene::Scene;
use state::RaytracingOption;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
mod bvh; mod bvh;
mod camera; mod camera;
@@ -33,143 +22,143 @@ mod state;
fn main() { fn main() {
env_logger::init(); env_logger::init();
env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
let args: Vec<String> = env::args().collect(); //let args: Vec<String> = env::args().collect();
if args.len() == 6 {
let width: usize = args[1].parse().unwrap();
let height: usize = args[2].parse().unwrap();
let fovy = args[3].parse::<f64>().unwrap();
let filename = &args[4];
let savefile = &args[5];
headless(
width,
height,
fovy,
filename.to_string(),
savefile.to_string(),
);
} else {
if let Err(e) = run() { if let Err(e) = run() {
println!("Error at runtime: {}", e); println!("Error at runtime: {}", e);
}; };
}
// if args.len() == 6 {
// let width: usize = args[1].parse().unwrap();
// let height: usize = args[2].parse().unwrap();
// let fovy = args[3].parse::<f64>().unwrap();
// let filename = &args[4];
// let savefile = &args[5];
// headless(
// width,
// height,
// fovy,
// filename.to_string(),
// savefile.to_string(),
// );
// } else {
//}
} }
fn headless(width: usize, height: usize, fovy: f64, filename: String, savefile: String) { // fn headless(width: usize, height: usize, fovy: f64, filename: String, savefile: String) {
let options = Arc::new(RaytracingOption { // let options = Arc::new(RaytracingOption {
threads: 12, // threads: 12,
ray_samples: 1, // ray_samples: 1,
ray_randomness: 100.0, // ray_randomness: 100.0,
clear_color: [0x22, 0x00, 0x11, 0x55], // clear_color: [0x22, 0x00, 0x11, 0x55],
pixel_clear: [0x55, 0x00, 0x22, 0x55], // pixel_clear: [0x55, 0x00, 0x22, 0x55],
pixels_per_thread: 200, // pixels_per_thread: 200,
buffer_proportion: 1.0, // buffer_proportion: 1.0,
buffer_fov: 110.0, // buffer_fov: 110.0,
ray_depth: 5, // ray_depth: 5,
diffuse_rays: 3, // diffuse_rays: 3,
diffuse_coefficient: 0.8, // diffuse_coefficient: 0.8,
bvh_active: false, // bvh_active: false,
}); // });
//Read script from file // //Read script from file
let script = match std::fs::read_to_string(&filename) { // let script = match std::fs::read_to_string(&filename) {
Ok(in_script) => in_script, // Ok(in_script) => in_script,
Err(e) => { // Err(e) => {
println!("{}", e); // println!("{}", e);
return; // return;
} // }
}; // };
//Evaluate scene in file // //Evaluate scene in file
let engine = init_engine(); // let engine = init_engine();
let scene: Arc<Scene> = match engine.eval(&script) { // let scene: Arc<Scene> = match engine.eval(&script) {
Ok(in_scene) => Arc::new(in_scene), // Ok(in_scene) => Arc::new(in_scene),
Err(e) => { // Err(e) => {
println!("{e}"); // println!("{e}");
return; // return;
} // }
}; // };
//Set the camera // //Set the camera
let mut camera = Camera::unit(); // let mut camera = Camera::unit();
for (_, in_camera) in &scene.cameras { // for (_, in_camera) in &scene.cameras {
camera = in_camera.clone(); // camera = in_camera.clone();
} // }
//Cast the rays // //Cast the rays
let rays = Arc::new(Ray::cast_rays( // let rays = Arc::new(Ray::cast_rays(
&camera.eye, // &camera.eye,
&camera.target, // &camera.target,
&camera.up, // &camera.up,
fovy, // fovy,
width as u32, // width as u32,
height as u32, // height as u32,
)); // ));
//Enable bounding volume heirarchy // //Enable bounding volume heirarchy
let bvh; // let bvh;
match options.bvh_active { // match options.bvh_active {
true => bvh = Arc::new(Some(BVH::build(&scene.nodes))), // true => bvh = Arc::new(Some(BVH::build(&scene.nodes))),
false => bvh = Arc::new(None), // false => bvh = Arc::new(None),
} // }
//Create our frame and indexer // //Create our frame and indexer
let size = width * height; // let size = width * height;
let frame_mutex = Arc::new(Mutex::new(vec![0; size * 4])); // let frame_mutex = Arc::new(Mutex::new(vec![0; size * 4]));
//Multithreading // //Multithreading
let mut handles = vec![]; // let mut handles = vec![];
for index in 0..size { // for index in 0..size {
for _ in 0..options.threads { // for _ in 0..options.threads {
//Get random index from queue // //Get random index from queue
//Create a nre thread for this pixel // //Create a nre thread for this pixel
let handle = thread::spawn({ // let handle = thread::spawn({
let rays = rays.clone(); // let rays = rays.clone();
let scene = scene.clone(); // let scene = scene.clone();
let options = options.clone(); // let options = options.clone();
let bvh = bvh.clone(); // let bvh = bvh.clone();
let rays = rays.clone(); // let rays = rays.clone();
let frame_mutex = frame_mutex.clone(); // let frame_mutex = frame_mutex.clone();
move || { // move || {
//Shade colour for selected ray // //Shade colour for selected ray
let mut colour: Vector3<f32> = Vector3::zeros(); // let mut colour: Vector3<f32> = Vector3::zeros();
//Get the ray we want to make // //Get the ray we want to make
let shot_ray = &rays[index]; // let shot_ray = &rays[index];
//Send out ray_samples rays // //Send out ray_samples rays
for _ in 0..options.ray_samples { // for _ in 0..options.ray_samples {
let point = shot_ray.a; // let point = shot_ray.a;
let dir = shot_ray.b; // let dir = shot_ray.b;
//Generate a random ray // //Generate a random ray
let rx = (random::<f64>() - 0.5) / options.ray_randomness; // let rx = (random::<f64>() - 0.5) / options.ray_randomness;
let ry = (random::<f64>() - 0.5) / options.ray_randomness; // let ry = (random::<f64>() - 0.5) / options.ray_randomness;
let rz = (random::<f64>() - 0.5) / options.ray_randomness; // let rz = (random::<f64>() - 0.5) / options.ray_randomness;
let nx = dir.x + rx; // let nx = dir.x + rx;
let ny = dir.y + ry; // let ny = dir.y + ry;
let nz = dir.z + rz; // let nz = dir.z + rz;
let rand_ray = Ray::new(point, Vector3::new(nx, ny, nz)); // let rand_ray = Ray::new(point, Vector3::new(nx, ny, nz));
if let Some(ray_colour) = rand_ray.shade_ray(&scene, 0, &options, &bvh) { // if let Some(ray_colour) = rand_ray.shade_ray(&scene, 0, &options, &bvh) {
colour += ray_colour; // colour += ray_colour;
} // }
} // }
colour = (colour / options.ray_samples as f32) * 255.0; // colour = (colour / options.ray_samples as f32) * 255.0;
let rgba = [colour.x as u8, colour.y as u8, colour.z as u8, 0xff]; // let rgba = [colour.x as u8, colour.y as u8, colour.z as u8, 0xff];
{ // {
let frame = &mut frame_mutex.lock().unwrap(); // let frame = &mut frame_mutex.lock().unwrap();
frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba); // frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba);
} // }
} // }
}); // });
handles.push(handle); // handles.push(handle);
} // }
for handle in handles.drain(..) { // for handle in handles.drain(..) {
handle.join().unwrap(); // handle.join().unwrap();
} // }
} // }
use std::path::Path; // use std::path::Path;
image::save_buffer( // image::save_buffer(
Path::new(&savefile), // Path::new(&savefile),
&frame_mutex.lock().unwrap(), // &frame_mutex.lock().unwrap(),
width as u32, // width as u32,
height as u32, // height as u32,
image::ColorType::Rgba8, // image::ColorType::Rgba8,
) // )
.unwrap(); // .unwrap();
} // }
fn log_error<E: Error + 'static>(method_name: &str, err: E) { fn log_error<E: Error + 'static>(method_name: &str, err: E) {
error!("{method_name}() failed: {err}"); error!("{method_name}() failed: {err}");

View File

@@ -1,8 +1,9 @@
use crate::{ use crate::{
bvh::AABB, bvh::AABB,
material::Material, material::Material,
primitive::{*}, primitive::*,
ray::{Intersection, Ray}, ray::{Intersection, Ray},
EPSILON,
}; };
use nalgebra::{Matrix4, Vector3}; use nalgebra::{Matrix4, Vector3};
use std::sync::Arc; use std::sync::Arc;
@@ -107,6 +108,9 @@ impl Node {
pub fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { pub fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let ray = ray.transform(&self.inv_model); //Transform from world coordinates let ray = ray.transform(&self.inv_model); //Transform from world coordinates
if let Some(mut intersect) = self.primitive.intersect_ray(&ray) { if let Some(mut intersect) = self.primitive.intersect_ray(&ray) {
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_model); //Transform to world coords
return Some(intersect); return Some(intersect);
} }

View File

@@ -70,8 +70,7 @@ impl Ray {
continue; continue;
} }
// Transform ray into local model cordinates // Transform ray into local model cordinates
let ray = ray.transform(&node.inv_model); if node.intersect_ray(&ray).is_some() {
if node.primitive.intersect_ray(&ray).is_some() {
return true; return true;
} }
} }
@@ -93,16 +92,13 @@ impl Ray {
} }
if node.aabb.intersect_ray(&ray) { if node.aabb.intersect_ray(&ray) {
// Transform ray into model cordinates //Check node intersection
let ray = ray.transform(&node.inv_model); if let Some(intersect) = node.intersect_ray(&ray) {
// Check primitive intersection
if let Some(mut intersect) = node.primitive.intersect_ray(&ray) {
// Dont intersect with own primitive // Dont intersect with own primitive
if intersect.distance < EPSILON { if intersect.distance < EPSILON {
continue; continue;
} }
// Check for closest distance by converting to world coords // Check for closest distance by converting to world coords
intersect.transform_mut(&node.model, &node.inv_model);
let distance = distance(&ray_a, &intersect.point); let distance = distance(&ray_a, &intersect.point);
if distance < closest_distance { if distance < closest_distance {
closest_distance = distance; closest_distance = distance;
@@ -162,9 +158,8 @@ impl Ray {
bvh: &Option<BVH>, bvh: &Option<BVH>,
) -> Vector3<f32> { ) -> Vector3<f32> {
let normal = &intersect.normal; let normal = &intersect.normal;
let point = intersect.point + normal * 0.0001; let point = &intersect.point;
let incidence = &ray.b; let incidence = &ray.b;
let material = &node.material; let material = &node.material;
// Compute the ambient light component and set it as base colour // Compute the ambient light component and set it as base colour
@@ -185,23 +180,28 @@ impl Ray {
let to_light = to_light.normalize(); let to_light = to_light.normalize();
//Niave Shadows //Niave Shadows
// let to_light_ray = Ray::new(point, to_light); if options.shadows {
// if to_light_ray.light_blocked(scene, node, bvh) { let to_light_ray = Ray::new(*point, to_light);
// continue; if to_light_ray.light_blocked(scene, node, bvh) {
// } continue;
}
}
let n_dot_l = normal.dot(&to_light).max(0.0) as f32; let n_dot_l = normal.dot(&to_light).max(0.0) as f32;
//Reflected component //Reflected component
let mut reflect = Vector3::zeros(); let mut reflect = Vector3::zeros();
if options.reflect {
let reflect_dir = incidence - 2.0 * incidence.dot(&normal) * normal; let reflect_dir = incidence - 2.0 * incidence.dot(&normal) * normal;
let reflect_ray = Ray::new(point, reflect_dir); let reflect_ray = Ray::new(*point, reflect_dir);
if let Some(col) = reflect_ray.shade_ray(scene, depth + 1, options, bvh) { if let Some(col) = reflect_ray.shade_ray(scene, depth + 1, options, bvh) {
reflect += col.component_mul(&material.kr) reflect += col.component_mul(&material.kr)
} }
}
//Diffuse component (Lambertian) //Diffuse component (Lambertian)
let mut diffuse = Vector3::zeros(); let mut diffuse = Vector3::zeros();
if options.diffuse {
diffuse += material.kd * n_dot_l; diffuse += material.kd * n_dot_l;
for _ in 0..options.diffuse_rays { for _ in 0..options.diffuse_rays {
let diffuse_dir = random_unit_vec(); let diffuse_dir = random_unit_vec();
@@ -210,20 +210,26 @@ impl Ray {
diffuse += col * options.diffuse_coefficient; diffuse += col * options.diffuse_coefficient;
} }
} }
}
//Specular component //Specular component
let mut specular = Vector3::zeros(); let mut specular = Vector3::zeros();
if options.specular {
if n_dot_l > 0.0 { if n_dot_l > 0.0 {
let h = (to_light - incidence).normalize(); let h = (to_light - incidence).normalize();
let n_dot_h = normal.dot(&h).max(0.0) as f32; let n_dot_h = normal.dot(&h).max(0.0) as f32;
specular = material.ks * n_dot_h.powf(material.shininess); specular = material.ks * n_dot_h.powf(material.shininess);
} }
}
//Falloff //Falloff
let falloff = 1.0 let mut falloff = 1.0;
if options.falloff {
falloff = 1.0
/ ((1.0 + light.falloff[0]) / ((1.0 + light.falloff[0])
+ light.falloff[1] * light_distance + light.falloff[1] * light_distance
+ light.falloff[2] * light_distance * light_distance); + light.falloff[2] * light_distance * light_distance);
}
let intensity = light.colour.component_mul(&(diffuse + reflect + specular)) * falloff; let intensity = light.colour.component_mul(&(diffuse + reflect + specular)) * falloff;
colour += &intensity; colour += &intensity;
@@ -253,8 +259,7 @@ impl Ray {
continue; continue;
} }
if node.aabb.intersect_ray(self) { if node.aabb.intersect_ray(self) {
let ray = self.transform(&node.inv_model); if node.intersect_ray(self).is_some() {
if node.primitive.intersect_ray(&ray).is_some() {
return true; return true;
} }
} }

View File

@@ -1,24 +1,6 @@
use crate::{camera::Camera, light::Light, material::*, node::*}; use crate::{camera::Camera, light::Light, material::*, node::*};
use std::collections::HashMap; use std::collections::HashMap;
// pub struct MultiThreadScene {
// pub nodes: Rc<HashMap<String, Node>>,
// pub materials: Rc<HashMap<String, Material>>,
// pub lights: Rc<HashMap<String, Light>>,
// pub cameras: Rc<HashMap<String, Camera>>,
// }
// impl MultiThreadScene {
// pub fn from_scene(scene: &Scene) -> MultiThreadScene {
// MultiThreadScene {
// nodes: Rc::new(scene.nodes.clone()),
// materials: Rc::new(scene.materials.clone()),
// lights: Rc::new(scene.lights.clone()),
// cameras: Rc::new(scene.cameras.clone()),
// }
// }
// }
#[derive(Clone)] #[derive(Clone)]
pub struct Scene { pub struct Scene {
pub nodes: HashMap<String, Node>, pub nodes: HashMap<String, Node>,
@@ -53,4 +35,10 @@ impl Scene {
pub fn add_camera(&mut self, label: String, camera: Camera) { pub fn add_camera(&mut self, label: String, camera: Camera) {
self.cameras.insert(label, camera); self.cameras.insert(label, camera);
} }
// Compute all matricies for nodes
pub fn compute(&mut self) {
for (_, node) in &mut self.nodes {
node.compute();
}
}
} }

View File

@@ -42,6 +42,11 @@ pub struct RaytracingOption {
pub diffuse_rays: u8, pub diffuse_rays: u8,
pub diffuse_coefficient: f32, pub diffuse_coefficient: f32,
pub bvh_active: bool, pub bvh_active: bool,
pub shadows: bool,
pub diffuse: bool,
pub reflect: bool,
pub specular: bool,
pub falloff: bool,
} }
impl RaytracingOption { impl RaytracingOption {
pub fn default() -> RaytracingOption { pub fn default() -> RaytracingOption {
@@ -58,6 +63,11 @@ impl RaytracingOption {
diffuse_rays: 3, diffuse_rays: 3,
diffuse_coefficient: 0.8, diffuse_coefficient: 0.8,
bvh_active: false, bvh_active: false,
shadows: true,
diffuse: true,
reflect: true,
specular: true,
falloff: true,
} }
} }
} }
@@ -228,6 +238,7 @@ impl State {
let mut colour: Vector3<f32> = Vector3::zeros(); let mut colour: Vector3<f32> = Vector3::zeros();
let ray = &rays[*index]; let ray = &rays[*index];
for _ in 0..samples { for _ in 0..samples {
//Generate a ray in a random direction
let point = ray.a; let point = ray.a;
let dir = ray.b; let dir = ray.b;
let rx = (random::<f64>() - 0.5) / randomness; let rx = (random::<f64>() - 0.5) / randomness;