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
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
if ui.button("Apply") {
self.event = Some(GuiEvent::RaytracerOption(self.raytracing_option.clone()));
@@ -346,9 +350,7 @@ impl Gui {
// SCENE --------------------------------------------
if CollapsingHeader::new("Scene").build(ui) {
if ui.button("Update Scene") {
for (_, node) in &mut self.scene.nodes {
node.compute();
}
self.scene.compute();
self.event = Some(GuiEvent::SceneLoad(self.scene.clone()));
}
// Edit transformation of nodes

View File

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

View File

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

View File

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

View File

@@ -1,24 +1,6 @@
use crate::{camera::Camera, light::Light, material::*, node::*};
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)]
pub struct Scene {
pub nodes: HashMap<String, Node>,
@@ -53,4 +35,10 @@ impl Scene {
pub fn add_camera(&mut self, label: String, camera: 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_coefficient: f32,
pub bvh_active: bool,
pub shadows: bool,
pub diffuse: bool,
pub reflect: bool,
pub specular: bool,
pub falloff: bool,
}
impl RaytracingOption {
pub fn default() -> RaytracingOption {
@@ -58,6 +63,11 @@ impl RaytracingOption {
diffuse_rays: 3,
diffuse_coefficient: 0.8,
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 ray = &rays[*index];
for _ in 0..samples {
//Generate a ray in a random direction
let point = ray.a;
let dir = ray.b;
let rx = (random::<f64>() - 0.5) / randomness;