Shadows, New rays and niceness
This commit is contained in:
36
scene.rhai
36
scene.rhai
@@ -1,35 +1,33 @@
|
|||||||
let scene = Scene();
|
let scene = Scene();
|
||||||
|
|
||||||
let eye = P(0.0, 0.0, 3.0);
|
|
||||||
let target = P(0.0, 0.0, 0.0);
|
|
||||||
let up = V(0.0, 1.0, 3.0);
|
|
||||||
|
|
||||||
let cam = Camera(eye, target, up, 70.0);
|
|
||||||
|
|
||||||
let material = Material(V(0.5,0.5,0.5), V(0.8, 0.8, 0.8), 25.0);
|
let material = Material(V(0.5,0.5,0.5), V(0.8, 0.8, 0.8), 25.0);
|
||||||
|
|
||||||
let ambient = Light(P(10.0,0.0,0.0), V(1.0,1.0,1.0), V(0.0, 0.0, 0.0));
|
//let ambient = Light(P(10.0,0.0,0.0), V(1.0,1.0,1.0), V(0.0, 0.0, 0.0));
|
||||||
|
//scene.addLight(ambient);
|
||||||
|
|
||||||
let light2 = Light(P(0.0,0.0,10.0), V(0.0,1.0,1.0), V(0.1, 0.01, 0.001));
|
let light = Light(P(3.0,3.0,1.0), V(0.0,1.0,1.0), V(0.1, 0.01, 0.001));
|
||||||
|
scene.addLight(light);
|
||||||
scene.addLight(light2);
|
|
||||||
scene.addLight(ambient);
|
|
||||||
|
|
||||||
|
|
||||||
// let sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
|
let sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
|
||||||
// let sphere_node = Node(sphere);
|
let sphere_node = Node(sphere);
|
||||||
|
// let child = sphere_node.child(sphere);
|
||||||
|
// child.translate(V(1.0,1.0,1.0));
|
||||||
// scene.addNode(sphere_node);
|
// scene.addNode(sphere_node);
|
||||||
|
// scene.addNode(child);
|
||||||
|
|
||||||
// let cube = CubeUnit(material);
|
// let cube = CubeUnit(material);
|
||||||
// let cube_node = Node(cube);
|
// let cube_node = Node(cube);
|
||||||
// scene.addNode(cube_node);
|
// scene.addNode(cube_node);
|
||||||
|
|
||||||
let gnonom = Gnonom(material);
|
// let gnonom = Gnonom(material);
|
||||||
let gnonom_node = Node(gnonom);
|
// let gnonom_node = Node(gnonom);
|
||||||
scene.addNode(gnonom_node);
|
// scene.addNode(gnonom_node);
|
||||||
|
|
||||||
// let cylinder = Cylinder(1.0,1.0, material);
|
let cylinder = Cylinder(1.0,1.0, material);
|
||||||
// let cylinder_node = Node(cylinder);
|
let cylinder_node = Node(cylinder);
|
||||||
// scene.addNode(cylinder_node);
|
cylinder_node.scale(V(4.0,0.3,0.3));
|
||||||
|
cylinder_node.translate(V(0.0,-4.0,1.0));
|
||||||
|
scene.addNode(cylinder_node);
|
||||||
|
|
||||||
scene
|
scene
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
use crate::ray::Ray;
|
use nalgebra::{Matrix4, Point3, Vector3};
|
||||||
use crate::{EPSILON, INFINITY};
|
|
||||||
use nalgebra::{Matrix4, Perspective3, Point3, Unit, Vector3};
|
|
||||||
|
|
||||||
const ZNEAR: f64 = EPSILON;
|
|
||||||
const ZFAR: f64 = INFINITY;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -11,8 +6,8 @@ pub struct Camera {
|
|||||||
eye: Point3<f64>,
|
eye: Point3<f64>,
|
||||||
target: Point3<f64>,
|
target: Point3<f64>,
|
||||||
up: Vector3<f64>,
|
up: Vector3<f64>,
|
||||||
view: Matrix4<f64>,
|
pub view: Matrix4<f64>,
|
||||||
inv_view: Matrix4<f64>,
|
pub inv_view: Matrix4<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
106
src/gui.rs
106
src/gui.rs
@@ -1,16 +1,24 @@
|
|||||||
use crate::{camera::Camera, scene::Scene, state::INIT_FILE, UP_VECTOR_F32, ZERO_VECTOR_F32};
|
use crate::{
|
||||||
|
camera::Camera,
|
||||||
|
light::Light,
|
||||||
|
primitive::*,
|
||||||
|
scene::{Node, Scene},
|
||||||
|
state::INIT_FILE,
|
||||||
|
UP_VECTOR_F32, ZERO_VECTOR_F32,
|
||||||
|
};
|
||||||
use imgui::*;
|
use imgui::*;
|
||||||
use nalgebra::{Point3, Vector3};
|
use nalgebra::{Point3, Vector3};
|
||||||
use pixels::{wgpu, PixelsContext};
|
use pixels::{wgpu, PixelsContext};
|
||||||
|
use rhai::Engine;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
const BUFFER_PROPORTION_INIT: f32 = 1.0;
|
const BUFFER_PROPORTION_INIT: f32 = 1.0;
|
||||||
const BUFFER_PROPORTION_MIN: f32 = 0.5;
|
const BUFFER_PROPORTION_MIN: f32 = 0.5;
|
||||||
const BUFFER_PROPORTION_MAX: f32 = 1.0;
|
const BUFFER_PROPORTION_MAX: f32 = 1.0;
|
||||||
|
|
||||||
const RAYS_INIT: i32 = 9000;
|
const RAYS_INIT: i32 = 1000;
|
||||||
const RAYS_MIN: i32 = 100;
|
const RAYS_MIN: i32 = 100;
|
||||||
const RAYS_MAX: i32 = 10000;
|
const RAYS_MAX: i32 = 100000;
|
||||||
|
|
||||||
const CAMERA_MIN_FOV: f32 = 10.0;
|
const CAMERA_MIN_FOV: f32 = 10.0;
|
||||||
const CAMERA_MAX_FOV: f32 = 160.0;
|
const CAMERA_MAX_FOV: f32 = 160.0;
|
||||||
@@ -18,7 +26,7 @@ const CAMERA_INIT: f32 = 5.0;
|
|||||||
|
|
||||||
/// Manages all state required for rendering Dear ImGui over `Pixels`test.
|
/// Manages all state required for rendering Dear ImGui over `Pixels`test.
|
||||||
pub enum GuiEvent {
|
pub enum GuiEvent {
|
||||||
BufferResize(f32),
|
BufferResize(f32, f32),
|
||||||
CameraUpdate(Camera),
|
CameraUpdate(Camera),
|
||||||
SceneLoad(Scene),
|
SceneLoad(Scene),
|
||||||
}
|
}
|
||||||
@@ -34,6 +42,7 @@ pub struct Gui {
|
|||||||
|
|
||||||
script_filename: String,
|
script_filename: String,
|
||||||
script: String,
|
script: String,
|
||||||
|
engine: Engine,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
|
|
||||||
pub ray_num: i32,
|
pub ray_num: i32,
|
||||||
@@ -63,7 +72,7 @@ impl Gui {
|
|||||||
|
|
||||||
// Configure Dear ImGui fonts
|
// Configure Dear ImGui fonts
|
||||||
let hidpi_factor = window.scale_factor();
|
let hidpi_factor = window.scale_factor();
|
||||||
let font_size = (11.0 * hidpi_factor) as f32;
|
let font_size = (16.0 * hidpi_factor) as f32;
|
||||||
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
||||||
imgui
|
imgui
|
||||||
.fonts()
|
.fonts()
|
||||||
@@ -96,6 +105,7 @@ impl Gui {
|
|||||||
|
|
||||||
script_filename: String::from(INIT_FILE),
|
script_filename: String::from(INIT_FILE),
|
||||||
script: String::new(),
|
script: String::new(),
|
||||||
|
engine: init_engine(),
|
||||||
scene: Scene::empty(),
|
scene: Scene::empty(),
|
||||||
|
|
||||||
ray_num: RAYS_INIT,
|
ray_num: RAYS_INIT,
|
||||||
@@ -156,9 +166,13 @@ impl Gui {
|
|||||||
BUFFER_PROPORTION_MAX,
|
BUFFER_PROPORTION_MAX,
|
||||||
&mut self.buffer_proportion,
|
&mut self.buffer_proportion,
|
||||||
);
|
);
|
||||||
|
ui.slider("fov", CAMERA_MIN_FOV, CAMERA_MAX_FOV, &mut self.camera_fov);
|
||||||
//Apply changes
|
//Apply changes
|
||||||
if ui.button("Apply") {
|
if ui.button("Apply") {
|
||||||
self.event = Some(GuiEvent::BufferResize(self.buffer_proportion));
|
self.event = Some(GuiEvent::BufferResize(
|
||||||
|
self.buffer_proportion,
|
||||||
|
self.camera_fov,
|
||||||
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//Camera options
|
//Camera options
|
||||||
@@ -167,7 +181,6 @@ impl Gui {
|
|||||||
ui.input_float3("Eye", &mut self.camera_eye).build();
|
ui.input_float3("Eye", &mut self.camera_eye).build();
|
||||||
ui.input_float3("Target", &mut self.camera_target).build();
|
ui.input_float3("Target", &mut self.camera_target).build();
|
||||||
ui.input_float3("Up", &mut self.camera_up).build();
|
ui.input_float3("Up", &mut self.camera_up).build();
|
||||||
ui.slider("fov", CAMERA_MIN_FOV, CAMERA_MAX_FOV, &mut self.camera_fov);
|
|
||||||
// Create three input fields for x, y, and z components
|
// Create three input fields for x, y, and z components
|
||||||
if ui.button("Apply Camera") {
|
if ui.button("Apply Camera") {
|
||||||
println!("Camera changed: {:?}", self.camera_eye);
|
println!("Camera changed: {:?}", self.camera_eye);
|
||||||
@@ -175,14 +188,10 @@ impl Gui {
|
|||||||
let (ex, ey, ez) = (eye[0] as f64, eye[1] as f64, eye[2] as f64);
|
let (ex, ey, ez) = (eye[0] as f64, eye[1] as f64, eye[2] as f64);
|
||||||
let (tx, ty, tz) = (target[0] as f64, target[1] as f64, target[2] as f64);
|
let (tx, ty, tz) = (target[0] as f64, target[1] as f64, target[2] as f64);
|
||||||
let (ux, uy, uz) = (up[0] as f64, up[1] as f64, up[2] as f64);
|
let (ux, uy, uz) = (up[0] as f64, up[1] as f64, up[2] as f64);
|
||||||
|
|
||||||
let camera = Camera::new(
|
let camera = Camera::new(
|
||||||
Point3::new(ex, ey, ez),
|
Point3::new(ex, ey, ez),
|
||||||
Point3::new(tx, ty, tz),
|
Point3::new(tx, ty, tz),
|
||||||
Vector3::new(ux, uy, uz),
|
Vector3::new(ux, uy, uz),
|
||||||
1,
|
|
||||||
1,
|
|
||||||
self.camera_fov as f64,
|
|
||||||
);
|
);
|
||||||
self.event = Some(GuiEvent::CameraUpdate(camera));
|
self.event = Some(GuiEvent::CameraUpdate(camera));
|
||||||
}
|
}
|
||||||
@@ -199,7 +208,7 @@ impl Gui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ui.button("Apply script") {
|
if ui.button("Apply script") {
|
||||||
match Scene::from_rhai(&self.script) {
|
match self.engine.eval(&self.script) {
|
||||||
Ok(scene) => {
|
Ok(scene) => {
|
||||||
self.scene = scene;
|
self.scene = scene;
|
||||||
self.event = Some(GuiEvent::SceneLoad(self.scene.clone()));
|
self.event = Some(GuiEvent::SceneLoad(self.scene.clone()));
|
||||||
@@ -208,7 +217,7 @@ impl Gui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Script block
|
//Script block
|
||||||
ui.input_text_multiline("script", &mut self.script, [500., 900.])
|
ui.input_text_multiline("script", &mut self.script, [600., 1500.])
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,3 +253,74 @@ impl Gui {
|
|||||||
.handle_event(self.imgui.io_mut(), window, event);
|
.handle_event(self.imgui.io_mut(), window, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_engine() -> Engine {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine
|
||||||
|
.register_type::<Vector3<f64>>()
|
||||||
|
.register_fn("V", Vector3::<f64>::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Point3<f64>>()
|
||||||
|
.register_fn("P", Point3::<f64>::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Camera>()
|
||||||
|
.register_fn("Camera", Camera::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Scene>()
|
||||||
|
.register_fn("Scene", Scene::empty)
|
||||||
|
.register_fn("addNode", Scene::add_node)
|
||||||
|
.register_fn("addLight", Scene::add_light);
|
||||||
|
|
||||||
|
engine
|
||||||
|
.register_type::<Node>()
|
||||||
|
.register_fn("Node", Node::new)
|
||||||
|
.register_fn("translate", Node::translate)
|
||||||
|
.register_fn("rotate", Node::rotate)
|
||||||
|
.register_fn("scale", Node::scale)
|
||||||
|
.register_fn("child", Node::child);
|
||||||
|
engine
|
||||||
|
.register_type::<Light>()
|
||||||
|
.register_fn("Light", Light::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Material>()
|
||||||
|
.register_fn("Material", Material::new)
|
||||||
|
.register_fn("MaterialRed", Material::red)
|
||||||
|
.register_fn("MaterialBlue", Material::blue)
|
||||||
|
.register_fn("MaterialGreen", Material::green)
|
||||||
|
.register_fn("MaterialMagenta", Material::magenta)
|
||||||
|
.register_fn("MaterialTurquoise", Material::turquoise);
|
||||||
|
engine
|
||||||
|
.register_type::<Sphere>()
|
||||||
|
.register_fn("Sphere", Sphere::new)
|
||||||
|
.register_fn("SphereUnit", Sphere::unit);
|
||||||
|
engine
|
||||||
|
.register_type::<Cube>()
|
||||||
|
.register_fn("Cube", Cube::new)
|
||||||
|
.register_fn("CubeUnit", Cube::unit);
|
||||||
|
engine
|
||||||
|
.register_type::<Cone>()
|
||||||
|
.register_fn("Cone", Cone::new)
|
||||||
|
.register_fn("ConeUnit", Cone::unit);
|
||||||
|
engine
|
||||||
|
.register_type::<Cylinder>()
|
||||||
|
.register_fn("Cylinder", Cylinder::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Circle>()
|
||||||
|
.register_fn("Circle", Circle::new)
|
||||||
|
.register_fn("CircleUnit", Circle::unit);
|
||||||
|
engine
|
||||||
|
.register_type::<Rectangle>()
|
||||||
|
.register_fn("Rectangle", Rectangle::new)
|
||||||
|
.register_fn("RectangleUnit", Rectangle::unit);
|
||||||
|
engine
|
||||||
|
.register_type::<SteinerSurface>()
|
||||||
|
.register_fn("Steiner", SteinerSurface::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Torus>()
|
||||||
|
.register_fn("Torus", Torus::new);
|
||||||
|
engine
|
||||||
|
.register_type::<Gnonom>()
|
||||||
|
.register_fn("Gnonom", Gnonom::new);
|
||||||
|
engine
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
@@ -1,7 +1,7 @@
|
|||||||
use crate::state::run;
|
use crate::state::run;
|
||||||
use error_iter::ErrorIter;
|
use error_iter::ErrorIter;
|
||||||
|
|
||||||
const EPSILON: f64 = 1e-9;
|
const EPSILON: f64 = 1e-6;
|
||||||
const INFINITY: f64 = f64::MAX;
|
const INFINITY: f64 = f64::MAX;
|
||||||
const EPSILON_VECTOR: Vector3<f64> = Vector3::new(EPSILON, EPSILON, EPSILON);
|
const EPSILON_VECTOR: Vector3<f64> = Vector3::new(EPSILON, EPSILON, EPSILON);
|
||||||
static ZERO_VECTOR: Vector3<f64> = Vector3::new(0.0, 0.0, 0.0);
|
static ZERO_VECTOR: Vector3<f64> = Vector3::new(0.0, 0.0, 0.0);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::{EPSILON, EPSILON_VECTOR, INFINITY};
|
use crate::{EPSILON, EPSILON_VECTOR, INFINITY};
|
||||||
use nalgebra::{distance, Point3, Unit, Vector3};
|
use nalgebra::{distance, Matrix4, Point3, Vector3};
|
||||||
use roots::{find_roots_cubic, find_roots_quadratic, find_roots_quartic, Roots};
|
use roots::{find_roots_quadratic, find_roots_quartic, Roots};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -54,11 +54,22 @@ impl Material {
|
|||||||
pub struct Intersection {
|
pub struct Intersection {
|
||||||
// Information about an intersection
|
// Information about an intersection
|
||||||
pub point: Point3<f64>,
|
pub point: Point3<f64>,
|
||||||
pub normal: Unit<Vector3<f64>>,
|
pub normal: Vector3<f64>,
|
||||||
pub incidence: Unit<Vector3<f64>>,
|
pub incidence: Vector3<f64>,
|
||||||
pub material: Arc<Material>,
|
pub material: Arc<Material>,
|
||||||
pub distance: f64,
|
pub distance: f64,
|
||||||
}
|
}
|
||||||
|
impl Intersection {
|
||||||
|
pub fn transform(&self, trans: &Matrix4<f64>, inv_trans: &Matrix4<f64>) -> Intersection {
|
||||||
|
Intersection {
|
||||||
|
point: trans.transform_point(&self.point),
|
||||||
|
normal: inv_trans.transpose().transform_vector(&self.normal),
|
||||||
|
incidence: trans.transform_vector(&self.incidence),
|
||||||
|
material: self.material.clone(),
|
||||||
|
distance: self.distance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BOUNDING BOX -----------------------------------------------------------------
|
// BOUNDING BOX -----------------------------------------------------------------
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -154,7 +165,7 @@ impl Primitive for Sphere {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let intersect = ray.at_t(t);
|
let intersect = ray.at_t(t);
|
||||||
let normal = Unit::new_normalize(intersect - self.position);
|
let normal = (intersect - self.position).normalize();
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal,
|
normal,
|
||||||
@@ -238,7 +249,7 @@ impl Primitive for Circle {
|
|||||||
false => {
|
false => {
|
||||||
return Some(Intersection {
|
return Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(self.normal),
|
normal: self.normal.normalize(),
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
material: Arc::clone(&self.material),
|
material: Arc::clone(&self.material),
|
||||||
distance: t,
|
distance: t,
|
||||||
@@ -329,9 +340,9 @@ impl Primitive for Cylinder {
|
|||||||
let normal = Vector3::new(2.0 * intersect.x, 0.0, 2.0 * intersect.z);
|
let normal = Vector3::new(2.0 * intersect.x, 0.0, 2.0 * intersect.z);
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(normal),
|
normal: normal,
|
||||||
material: Arc::clone(&self.material),
|
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
|
material: Arc::clone(&self.material),
|
||||||
distance: t,
|
distance: t,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -462,9 +473,9 @@ impl Primitive for Cone {
|
|||||||
match intersect.y >= self.base && intersect.y <= self.apex {
|
match intersect.y >= self.base && intersect.y <= self.apex {
|
||||||
true => Some(Intersection {
|
true => Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(self.get_normal(intersect)),
|
normal: self.get_normal(intersect),
|
||||||
material: Arc::clone(&self.material),
|
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
|
material: Arc::clone(&self.material),
|
||||||
distance: t,
|
distance: t,
|
||||||
}),
|
}),
|
||||||
false => None,
|
false => None,
|
||||||
@@ -568,7 +579,7 @@ impl Primitive for Rectangle {
|
|||||||
if pi_dot_r1 >= -w2 && pi_dot_r1 <= w2 && pi_dot_r2 >= -h2 && pi_dot_r2 <= h2 {
|
if pi_dot_r1 >= -w2 && pi_dot_r1 <= w2 && pi_dot_r2 >= -h2 && pi_dot_r2 <= h2 {
|
||||||
return Some(Intersection {
|
return Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(self.normal),
|
normal: self.normal,
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
material: Arc::clone(&self.material),
|
material: Arc::clone(&self.material),
|
||||||
distance: t,
|
distance: t,
|
||||||
@@ -657,7 +668,7 @@ impl Primitive for Cube {
|
|||||||
|
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(normal),
|
normal: normal,
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
material: Arc::clone(&self.material),
|
material: Arc::clone(&self.material),
|
||||||
distance: tmin,
|
distance: tmin,
|
||||||
@@ -748,7 +759,7 @@ impl Primitive for Triangle {
|
|||||||
{
|
{
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: Unit::new_normalize(normal),
|
normal: normal,
|
||||||
incidence: ray.b,
|
incidence: ray.b,
|
||||||
material: Arc::clone(&self.material),
|
material: Arc::clone(&self.material),
|
||||||
distance: t,
|
distance: t,
|
||||||
@@ -958,11 +969,12 @@ impl Primitive for SteinerSurface {
|
|||||||
//Now we have the smallest non-zero t
|
//Now we have the smallest non-zero t
|
||||||
let point = ray.at_t(t);
|
let point = ray.at_t(t);
|
||||||
let (x, y, z) = (point.x, point.y, point.z);
|
let (x, y, z) = (point.x, point.y, point.z);
|
||||||
let normal = Unit::new_normalize(Vector3::new(
|
let normal = Vector3::new(
|
||||||
2.0 * x * y * y + 2.0 * x * z * z + y * z,
|
2.0 * x * y * y + 2.0 * x * z * z + y * z,
|
||||||
2.0 * x * x * y + 2.0 * z * z * y + x * z,
|
2.0 * x * x * y + 2.0 * z * z * y + x * z,
|
||||||
2.0 * x * x * z + 2.0 * z * y * y + x * y,
|
2.0 * x * x * z + 2.0 * z * y * y + x * y,
|
||||||
));
|
)
|
||||||
|
.normalize();
|
||||||
|
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point,
|
point,
|
||||||
@@ -1106,7 +1118,7 @@ impl Primitive for Torus {
|
|||||||
-4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r1;
|
-4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r1;
|
||||||
let dz = -8.0 * r2.powf(2.0) * x
|
let dz = -8.0 * r2.powf(2.0) * x
|
||||||
+ 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x;
|
+ 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x;
|
||||||
let normal = Unit::new_normalize(Vector3::new(dx, dy, dz));
|
let normal = Vector3::new(dx, dy, dz).normalize();
|
||||||
|
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point,
|
point,
|
||||||
|
|||||||
61
src/ray.rs
61
src/ray.rs
@@ -1,83 +1,102 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
primitive::Intersection,
|
primitive::{self, Intersection},
|
||||||
raytracer::phong_shade_point,
|
raytracer::phong_shade_point,
|
||||||
scene::{Node, Scene},
|
scene::{Node, Scene},
|
||||||
EPSILON, INFINITY,
|
EPSILON, INFINITY,
|
||||||
};
|
};
|
||||||
use nalgebra::{Point3, Unit, Vector3};
|
use nalgebra::{Matrix4, Point3, Vector3};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Ray {
|
pub struct Ray {
|
||||||
pub a: Point3<f64>,
|
pub a: Point3<f64>,
|
||||||
pub b: Unit<Vector3<f64>>,
|
pub b: Vector3<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ray {
|
impl Ray {
|
||||||
pub fn new(a: Point3<f64>, b: Unit<Vector3<f64>>) -> Ray {
|
pub fn new(a: Point3<f64>, b: Vector3<f64>) -> Ray {
|
||||||
Ray { a, b }
|
Ray {
|
||||||
|
a,
|
||||||
|
b: b.normalize(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn unit() -> Ray {
|
pub fn unit() -> Ray {
|
||||||
let a = Point3::new(0.0, 0.0, 0.0);
|
let a = Point3::new(0.0, 0.0, 0.0);
|
||||||
let b = Unit::new_normalize(Vector3::new(0.0, 1.0, 0.0));
|
let b = Vector3::new(0.0, 1.0, 0.0);
|
||||||
Ray { a, b }
|
Ray { a, b }
|
||||||
}
|
}
|
||||||
pub fn at_t(&self, t: f64) -> Point3<f64> {
|
pub fn at_t(&self, t: f64) -> Point3<f64> {
|
||||||
self.a + self.b.into_inner() * (t + EPSILON)
|
self.a + self.b * t
|
||||||
}
|
}
|
||||||
//Shade a single ray
|
//Shade a single ray
|
||||||
pub fn shade_ray(&self, scene: &Scene) -> Option<Vector3<u8>> {
|
pub fn shade_ray(&self, scene: &Scene) -> Option<Vector3<u8>> {
|
||||||
let intersect = self.get_closest_intersection(&scene.nodes);
|
let intersect = self.get_closest_intersection(&scene.nodes);
|
||||||
|
|
||||||
match intersect {
|
match intersect {
|
||||||
Some(intersect) => Some(phong_shade_point(&scene, &intersect)),
|
Some(intersect) => Some(phong_shade_point(&scene, &intersect)),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the closest intersection, given a ray in world coordinates
|
// Find the closest intersection
|
||||||
pub fn get_closest_intersection(&self, nodes: &Vec<Node>) -> Option<Intersection> {
|
pub fn get_closest_intersection(&self, nodes: &Vec<Node>) -> Option<Intersection> {
|
||||||
let mut closest_distance = INFINITY;
|
let mut closest_distance = INFINITY;
|
||||||
let mut closest_intersect: Option<Intersection> = None;
|
let mut closest_intersect: Option<Intersection> = None;
|
||||||
|
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
let primitive = node.primitive.clone();
|
let primitive = node.primitive.clone();
|
||||||
let trans = node.trans;
|
|
||||||
let inv_trans = node.inv_trans;
|
|
||||||
|
|
||||||
if let Some(intersect) = primitive.intersect_ray(self) {
|
//Transform ray to view coords
|
||||||
|
let ray = self.transform(&node.inv_viewmodel);
|
||||||
|
|
||||||
|
if primitive.intersect_bounding_box(&ray).is_some() {
|
||||||
|
if let Some(intersect) = primitive.intersect_ray(&ray) {
|
||||||
if intersect.distance < closest_distance {
|
if intersect.distance < closest_distance {
|
||||||
closest_distance = intersect.distance;
|
closest_distance = intersect.distance;
|
||||||
|
//Convert back to world coords
|
||||||
|
let intersect = intersect.transform(&node.model, &node.inv_model);
|
||||||
closest_intersect = Some(intersect);
|
closest_intersect = Some(intersect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
closest_intersect
|
closest_intersect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transform(&self, trans: &Matrix4<f64>) -> Ray {
|
||||||
|
Ray {
|
||||||
|
a: trans.transform_point(&self.a),
|
||||||
|
b: trans.transform_vector(&self.b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cast_rays(fovy: f64, width: u32, height: u32) -> Vec<Ray> {
|
pub fn cast_rays(fovy: f64, width: u32, height: u32) -> Vec<Ray> {
|
||||||
let aspect = width as f64 / height as f64;
|
let aspect = width as f64 / height as f64;
|
||||||
let fovy_radians = fovy.to_radians();
|
let fovy_radians = fovy.to_radians();
|
||||||
//Verify this part later
|
let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan();
|
||||||
|
|
||||||
let dir = Vector3::new(0.0, 0.0, 1.0);
|
let dir = Vector3::new(0.0, 0.0, 1.0);
|
||||||
let up = Vector3::new(0.0, 1.0, 0.0);
|
let up = Vector3::new(0.0, 1.0, 0.0);
|
||||||
let hor = Vector3::new(1.0, 0.0, 0.0);
|
let hor = Vector3::new(1.0, 0.0, 0.0);
|
||||||
let half_height = fovy_radians.tan();
|
let vheight = 2.0 * (fovy_radians / 2.0).tan();
|
||||||
let half_width = aspect * half_height;
|
let vwidth = 2.0 * (fovh_radians / 2.0).tan();
|
||||||
|
|
||||||
let d_hor_vec = hor * (2.0 * half_width / width as f64) as f64;
|
let d_hor_vec = hor * (vwidth / width as f64) as f64;
|
||||||
let d_vert_vec = up * (2.0 * half_height / height as f64) as f64;
|
let d_vert_vec = up * (vheight / height as f64) as f64;
|
||||||
|
|
||||||
//All good
|
let half_width = width / 2;
|
||||||
|
let half_height = height / 2;
|
||||||
|
|
||||||
let mut rays = Vec::with_capacity(width as usize * height as usize);
|
let mut rays = Vec::with_capacity(width as usize * height as usize);
|
||||||
|
|
||||||
for j in 0..height as i32 {
|
for j in 0..height as i32 {
|
||||||
for i in 0..width as i32 {
|
for i in 0..width as i32 {
|
||||||
let horizontal = (i - half_width as i32) as f64 * (d_hor_vec);
|
let x = i - half_width as i32;
|
||||||
let vertical = (-j + half_height as i32) as f64 * (d_vert_vec);
|
let y = -j + half_height as i32;
|
||||||
|
let horizontal = x as f64 * d_hor_vec;
|
||||||
|
let vertical = y as f64 * (d_vert_vec);
|
||||||
let direction = dir + horizontal + vertical;
|
let direction = dir + horizontal + vertical;
|
||||||
let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), Unit::new_normalize(direction));
|
let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), direction);
|
||||||
rays.push(ray);
|
rays.push(ray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{light::Light, primitive::Intersection, scene::*, ZERO_VECTOR};
|
use crate::{light::Light, primitive::Intersection, ray::Ray, scene::*, EPSILON, ZERO_VECTOR};
|
||||||
|
|
||||||
use nalgebra::{Unit, Vector3};
|
use nalgebra::{Unit, Vector3};
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
|||||||
material,
|
material,
|
||||||
..
|
..
|
||||||
} = intersect;
|
} = intersect;
|
||||||
|
|
||||||
let kd = material.kd;
|
let kd = material.kd;
|
||||||
let ks = material.ks;
|
let ks = material.ks;
|
||||||
let shininess = material.shininess;
|
let shininess = material.shininess;
|
||||||
@@ -28,9 +29,15 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
|||||||
// Point to light
|
// Point to light
|
||||||
let to_light = light_position - point;
|
let to_light = light_position - point;
|
||||||
let light_distance = to_light.norm();
|
let light_distance = to_light.norm();
|
||||||
let to_light = Unit::new_normalize(to_light);
|
let to_light = to_light;
|
||||||
|
|
||||||
|
let to_light_ray = Ray::new(point.clone() + normal * EPSILON, to_light);
|
||||||
|
if light_blocked(scene, to_light_ray) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Point to camera
|
// Point to camera
|
||||||
let to_camera = Unit::new_normalize(-incidence.into_inner());
|
let to_camera = -incidence;
|
||||||
// Diffuse component
|
// Diffuse component
|
||||||
let n_dot_l = normal.dot(&to_light).max(0.0);
|
let n_dot_l = normal.dot(&to_light).max(0.0);
|
||||||
let diffuse = n_dot_l * kd;
|
let diffuse = n_dot_l * kd;
|
||||||
@@ -58,3 +65,15 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
|||||||
let (r, g, b) = (colour.x as u8, colour.y as u8, colour.z as u8);
|
let (r, g, b) = (colour.x as u8, colour.y as u8, colour.z as u8);
|
||||||
Vector3::new(r, g, b)
|
Vector3::new(r, g, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn light_blocked(scene: &Scene, ray: Ray) -> bool {
|
||||||
|
for node in &scene.nodes {
|
||||||
|
let ray = ray.transform(&node.inv_model);
|
||||||
|
if node.primitive.intersect_bounding_box(&ray).is_some() {
|
||||||
|
if node.primitive.intersect_ray(&ray).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|||||||
149
src/scene.rs
149
src/scene.rs
@@ -1,38 +1,66 @@
|
|||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
use crate::light::Light;
|
use crate::light::Light;
|
||||||
use crate::primitive::*;
|
use crate::primitive::*;
|
||||||
use nalgebra::{Matrix4, Point3, Vector3};
|
use nalgebra::{Matrix4, Vector3};
|
||||||
use rhai::{Engine, EvalAltResult};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
pub primitive: Arc<dyn Primitive>,
|
pub primitive: Arc<dyn Primitive>,
|
||||||
pub model_transform: Matrix4<f32>,
|
pub model: Matrix4<f64>,
|
||||||
|
pub inv_model: Matrix4<f64>,
|
||||||
|
pub viewmodel: Matrix4<f64>,
|
||||||
|
pub inv_viewmodel: Matrix4<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn new(primitive: Arc<dyn Primitive>) -> Self {
|
pub fn new(primitive: Arc<dyn Primitive>) -> Node {
|
||||||
Node {
|
Node {
|
||||||
primitive,
|
primitive,
|
||||||
model_transform: Matrix4::identity(),
|
model: Matrix4::identity(),
|
||||||
|
inv_model: Matrix4::identity(),
|
||||||
|
viewmodel: Matrix4::identity(),
|
||||||
|
inv_viewmodel: Matrix4::identity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn rotate(&mut self, roll: f32, pitch: f32, yaw: f32) {
|
pub fn rotate(&mut self, roll: f64, pitch: f64, yaw: f64) {
|
||||||
let roll = (roll as f64).to_radians() as f32;
|
let roll = roll.to_radians();
|
||||||
let pitch = (pitch as f64).to_radians() as f32;
|
let pitch = pitch.to_radians();
|
||||||
let yaw = (yaw as f64).to_radians() as f32;
|
let yaw = yaw.to_radians();
|
||||||
let rotation_matrix = Matrix4::from_euler_angles(roll, pitch, yaw);
|
let rotation_matrix = Matrix4::from_euler_angles(roll, pitch, yaw);
|
||||||
self.model_transform = rotation_matrix * self.model_transform;
|
self.model = rotation_matrix * self.model;
|
||||||
|
self.inv_model = self.model.try_inverse().unwrap();
|
||||||
|
self.viewmodel = rotation_matrix * self.viewmodel;
|
||||||
|
self.inv_viewmodel = self.inv_viewmodel.try_inverse().unwrap();
|
||||||
}
|
}
|
||||||
pub fn translate(&mut self, translation: &Vector3<f32>) {
|
pub fn translate(&mut self, translation: Vector3<f64>) {
|
||||||
let translation_matrix = Matrix4::new_translation(translation);
|
let translation_matrix = Matrix4::new_translation(&translation);
|
||||||
self.model_transform = translation_matrix * self.model_transform;
|
self.model = translation_matrix * self.model;
|
||||||
|
self.inv_model = self.model.try_inverse().unwrap();
|
||||||
|
self.viewmodel = translation_matrix * self.viewmodel;
|
||||||
|
self.inv_viewmodel = self.inv_viewmodel.try_inverse().unwrap();
|
||||||
}
|
}
|
||||||
pub fn scale(&mut self, scale: &Vector3<f32>) {
|
pub fn scale(&mut self, scale: Vector3<f64>) {
|
||||||
let scale_matrix = Matrix4::new_nonuniform_scaling(scale);
|
let scale_matrix = Matrix4::new_nonuniform_scaling(&scale);
|
||||||
self.model_transform = scale_matrix * self.model_transform;
|
self.model = scale_matrix * self.model;
|
||||||
|
self.inv_model = self.model.try_inverse().unwrap();
|
||||||
|
self.viewmodel = scale_matrix * self.viewmodel;
|
||||||
|
self.inv_viewmodel = self.inv_viewmodel.try_inverse().unwrap();
|
||||||
|
}
|
||||||
|
pub fn child(self, primitive: Arc<dyn Primitive>) -> Node {
|
||||||
|
Node {
|
||||||
|
primitive,
|
||||||
|
model: self.model,
|
||||||
|
inv_model: self.inv_model,
|
||||||
|
viewmodel: self.model,
|
||||||
|
inv_viewmodel: self.inv_model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn compute(&mut self, view: &Matrix4<f64>, inv_view: &Matrix4<f64>) {
|
||||||
|
self.viewmodel = view * self.model;
|
||||||
|
self.inv_viewmodel = self.inv_model * inv_view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
pub nodes: Vec<Node>,
|
pub nodes: Vec<Node>,
|
||||||
@@ -51,94 +79,21 @@ impl Scene {
|
|||||||
cameras: Vec::new(),
|
cameras: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_node(&mut self, node: Node) {
|
pub fn add_node(&mut self, node: Node) {
|
||||||
self.nodes.push(node);
|
self.nodes.push(node);
|
||||||
}
|
}
|
||||||
fn add_material(&mut self, material: Material) {
|
pub fn add_material(&mut self, material: Material) {
|
||||||
self.materials.push(material);
|
self.materials.push(material);
|
||||||
}
|
}
|
||||||
fn add_light(&mut self, light: Light) {
|
pub fn add_light(&mut self, light: Light) {
|
||||||
self.lights.push(light);
|
self.lights.push(light);
|
||||||
}
|
}
|
||||||
fn add_camera(&mut self, camera: Camera) {
|
pub fn add_camera(&mut self, camera: Camera) {
|
||||||
self.cameras.push(camera);
|
self.cameras.push(camera);
|
||||||
}
|
}
|
||||||
|
pub fn compute(&mut self, view: &Matrix4<f64>, inv_view: &Matrix4<f64>) {
|
||||||
pub fn from_rhai(script: &str) -> Result<Scene, Box<EvalAltResult>> {
|
for node in &mut self.nodes {
|
||||||
let mut engine = Engine::new();
|
node.compute(view, inv_view);
|
||||||
|
}
|
||||||
engine
|
|
||||||
.register_type::<Vector3<f64>>()
|
|
||||||
.register_fn("V", Vector3::<f64>::new);
|
|
||||||
engine
|
|
||||||
.register_type::<Point3<f64>>()
|
|
||||||
.register_fn("P", Point3::<f64>::new);
|
|
||||||
engine
|
|
||||||
.register_type::<Scene>()
|
|
||||||
.register_fn("Scene", Scene::empty)
|
|
||||||
.register_fn("addNode", Scene::add_node)
|
|
||||||
.register_fn("addLight", Scene::add_light);
|
|
||||||
|
|
||||||
engine
|
|
||||||
.register_type::<Node>()
|
|
||||||
.register_fn("Node", Node::new)
|
|
||||||
.register_fn("translate", Node::translate)
|
|
||||||
.register_fn("rotate", Node::rotate)
|
|
||||||
.register_fn("scale", Node::scale);
|
|
||||||
engine
|
|
||||||
.register_type::<Camera>()
|
|
||||||
.register_fn("Camera", Camera::new_sizeless);
|
|
||||||
engine
|
|
||||||
.register_type::<Light>()
|
|
||||||
.register_fn("Light", Light::new);
|
|
||||||
engine
|
|
||||||
.register_type::<Material>()
|
|
||||||
.register_fn("Material", Material::new)
|
|
||||||
.register_fn("MaterialRed", Material::red)
|
|
||||||
.register_fn("MaterialBlue", Material::blue)
|
|
||||||
.register_fn("MaterialGreen", Material::green)
|
|
||||||
.register_fn("MaterialMagenta", Material::magenta)
|
|
||||||
.register_fn("MaterialTurquoise", Material::turquoise);
|
|
||||||
engine
|
|
||||||
.register_type::<Sphere>()
|
|
||||||
.register_fn("Sphere", Sphere::new)
|
|
||||||
.register_fn("SphereUnit", Sphere::unit);
|
|
||||||
engine
|
|
||||||
.register_type::<Cube>()
|
|
||||||
.register_fn("Cube", Cube::new)
|
|
||||||
.register_fn("CubeUnit", Cube::unit);
|
|
||||||
engine
|
|
||||||
.register_type::<Cone>()
|
|
||||||
.register_fn("Cone", Cone::new)
|
|
||||||
.register_fn("ConeUnit", Cone::unit);
|
|
||||||
engine
|
|
||||||
.register_type::<Cylinder>()
|
|
||||||
.register_fn("Cylinder", Cylinder::new);
|
|
||||||
engine
|
|
||||||
.register_type::<Circle>()
|
|
||||||
.register_fn("Circle", Circle::new)
|
|
||||||
.register_fn("CircleUnit", Circle::unit);
|
|
||||||
engine
|
|
||||||
.register_type::<Rectangle>()
|
|
||||||
.register_fn("Rectangle", Rectangle::new)
|
|
||||||
.register_fn("RectangleUnit", Rectangle::unit);
|
|
||||||
engine
|
|
||||||
.register_type::<SteinerSurface>()
|
|
||||||
.register_fn("Steiner", SteinerSurface::new);
|
|
||||||
engine
|
|
||||||
.register_type::<Torus>()
|
|
||||||
.register_fn("Torus", Torus::new);
|
|
||||||
engine
|
|
||||||
.register_type::<AdamShape>()
|
|
||||||
.register_fn("Adam", AdamShape::new);
|
|
||||||
engine
|
|
||||||
.register_type::<AdamShape2>()
|
|
||||||
.register_fn("Adam2", AdamShape2::new);
|
|
||||||
engine
|
|
||||||
.register_type::<AdamShape3>()
|
|
||||||
.register_fn("Adam3", AdamShape3::new);
|
|
||||||
|
|
||||||
let scene: Scene = engine.eval(script.into())?;
|
|
||||||
Ok(scene)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/state.rs
41
src/state.rs
@@ -1,6 +1,7 @@
|
|||||||
//Use linear algebra module
|
//Use linear algebra module
|
||||||
|
|
||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
|
use crate::ray::Ray;
|
||||||
use crate::{gui::Gui, scene::Scene};
|
use crate::{gui::Gui, scene::Scene};
|
||||||
use crate::{gui::GuiEvent, log_error};
|
use crate::{gui::GuiEvent, log_error};
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ pub struct State {
|
|||||||
pixels: Arc<Mutex<Pixels>>,
|
pixels: Arc<Mutex<Pixels>>,
|
||||||
gui: Gui,
|
gui: Gui,
|
||||||
|
|
||||||
|
rays: Vec<Ray>,
|
||||||
ray_queue: Vec<usize>,
|
ray_queue: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +45,7 @@ impl State {
|
|||||||
let scene = Scene::empty();
|
let scene = Scene::empty();
|
||||||
let window_size = window.inner_size();
|
let window_size = window.inner_size();
|
||||||
let camera = Camera::unit();
|
let camera = Camera::unit();
|
||||||
|
let rays = Vec::new();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
scene,
|
scene,
|
||||||
@@ -52,6 +55,7 @@ impl State {
|
|||||||
buffer_height: window_size.height as u32,
|
buffer_height: window_size.height as u32,
|
||||||
pixels: Arc::new(Mutex::new(pixels)),
|
pixels: Arc::new(Mutex::new(pixels)),
|
||||||
gui,
|
gui,
|
||||||
|
rays,
|
||||||
ray_queue: Vec::new(),
|
ray_queue: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,25 +63,33 @@ impl State {
|
|||||||
fn update(&mut self) -> Result<(), Box<dyn Error>> {
|
fn update(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
if let Some(event) = self.gui.event.take() {
|
if let Some(event) = self.gui.event.take() {
|
||||||
match event {
|
match event {
|
||||||
GuiEvent::BufferResize(proportion) => self.resize_buffer(proportion)?,
|
GuiEvent::BufferResize(proportion, fov) => {
|
||||||
GuiEvent::CameraUpdate(camera) => self.set_camera(camera)?,
|
self.resize_buffer(proportion, fov as f64)?
|
||||||
|
}
|
||||||
|
GuiEvent::CameraUpdate(camera) => {
|
||||||
|
self.camera = camera;
|
||||||
|
self.clear()?;
|
||||||
|
self.reset_queue();
|
||||||
|
}
|
||||||
GuiEvent::SceneLoad(scene) => {
|
GuiEvent::SceneLoad(scene) => {
|
||||||
self.scene = scene;
|
self.scene = scene;
|
||||||
self.clear()?;
|
self.reset_queue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_buffer(&mut self, proportion: f32) -> Result<(), Box<dyn Error>> {
|
fn resize_buffer(&mut self, proportion: f32, fovy: f64) -> Result<(), Box<dyn Error>> {
|
||||||
let size = self.window.inner_size();
|
let size = self.window.inner_size();
|
||||||
|
|
||||||
self.buffer_width = (size.width as f32 * proportion) as u32;
|
self.buffer_width = (size.width as f32 * proportion) as u32;
|
||||||
self.buffer_height = (size.height as f32 * proportion) as u32;
|
self.buffer_height = (size.height as f32 * proportion) as u32;
|
||||||
self.camera.set_size(self.buffer_width, self.buffer_height);
|
|
||||||
|
|
||||||
self.clear()?;
|
self.clear()?;
|
||||||
|
self.reset_queue();
|
||||||
|
|
||||||
|
self.rays = Ray::cast_rays(fovy, self.buffer_width, self.buffer_height);
|
||||||
|
|
||||||
let mut pixels = self.pixels.lock().unwrap();
|
let mut pixels = self.pixels.lock().unwrap();
|
||||||
pixels.resize_buffer(self.buffer_width, self.buffer_height)?;
|
pixels.resize_buffer(self.buffer_width, self.buffer_height)?;
|
||||||
@@ -85,6 +97,9 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&mut self, size: &PhysicalSize<u32>) -> Result<(), Box<dyn Error>> {
|
fn resize(&mut self, size: &PhysicalSize<u32>) -> Result<(), Box<dyn Error>> {
|
||||||
|
self.buffer_width = (size.width) as u32;
|
||||||
|
self.buffer_height = (size.height) as u32;
|
||||||
|
self.reset_queue();
|
||||||
let mut pixels = self.pixels.lock().unwrap();
|
let mut pixels = self.pixels.lock().unwrap();
|
||||||
pixels.resize_surface(size.width, size.height)?;
|
pixels.resize_surface(size.width, size.height)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -105,7 +120,7 @@ impl State {
|
|||||||
//Get random index from queue
|
//Get random index from queue
|
||||||
let index = self.ray_queue.pop().unwrap();
|
let index = self.ray_queue.pop().unwrap();
|
||||||
//Shade colour for selected ray
|
//Shade colour for selected ray
|
||||||
let colour = &self.camera.rays[index].shade_ray(&self.scene);
|
let colour = &self.rays[index].shade_ray(&self.scene);
|
||||||
//Assign colour to frame
|
//Assign colour to frame
|
||||||
let rgba = colour.map_or(COLOUR_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]);
|
let rgba = colour.map_or(COLOUR_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]);
|
||||||
let mut pixels = self.pixels.lock().unwrap();
|
let mut pixels = self.pixels.lock().unwrap();
|
||||||
@@ -128,19 +143,12 @@ impl State {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_camera(&mut self, camera: Camera) -> Result<(), Box<dyn Error>> {
|
|
||||||
self.clear()?;
|
|
||||||
self.reset_queue();
|
|
||||||
self.camera = camera;
|
|
||||||
self.camera.set_size(self.buffer_width, self.buffer_height);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_queue(&mut self) {
|
fn reset_queue(&mut self) {
|
||||||
let size = self.buffer_height as usize * self.buffer_width as usize;
|
let size = self.buffer_height as usize * self.buffer_width as usize;
|
||||||
let mut ray_queue: Vec<usize> = (0..size).collect();
|
let mut ray_queue: Vec<usize> = (0..size).collect();
|
||||||
ray_queue.shuffle(&mut thread_rng());
|
ray_queue.shuffle(&mut thread_rng());
|
||||||
self.ray_queue = ray_queue;
|
self.ray_queue = ray_queue;
|
||||||
|
self.scene.compute(&self.camera.view, &self.camera.inv_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self) -> Result<(), Box<dyn Error>> {
|
fn render(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
@@ -171,7 +179,7 @@ pub fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
let gui = Gui::new(&window, &pixels);
|
let gui = Gui::new(&window, &pixels);
|
||||||
|
|
||||||
let mut state = State::new(window, pixels, gui);
|
let mut state = State::new(window, pixels, gui);
|
||||||
state.resize_buffer(1.0)?;
|
state.resize_buffer(1.0, 90.0)?;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
state.gui.handle_event(&state.window, &event);
|
state.gui.handle_event(&state.window, &event);
|
||||||
@@ -186,6 +194,7 @@ pub fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
if let Err(_e) = state.render() {
|
if let Err(_e) = state.render() {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
@@ -193,7 +202,7 @@ pub fn run() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
_ => state.window.request_redraw(),
|
_ => state.window.request_redraw(),
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_window(event_loop: &EventLoop<()>) -> Window {
|
fn create_window(event_loop: &EventLoop<()>) -> Window {
|
||||||
|
|||||||
Reference in New Issue
Block a user