Working scripting

This commit is contained in:
STP
2023-11-19 15:33:04 -05:00
parent 7d04822b1f
commit f31ebb06bd
5 changed files with 236 additions and 132 deletions

View File

@@ -20,4 +20,4 @@ winit = "0.27"
winit_input_helper = "0.13"
pixels = "0.13"
error-iter = "0.4.1"
rhai = "1.16.3"
rhai = {version = "1.16.3", features=["f32_float"]}

View File

@@ -39,20 +39,19 @@ const EPSILON_VECTOR: Vector3<f32> = Vector3::new(EPSILON, EPSILON, EPSILON);
const INFINITY_VECTOR: Vector3<f32> = Vector3::new(INFINITY, INFINITY, INFINITY);
struct State {
scene: Arc<Scene>,
scene: Scene,
window: Window,
pixels: Arc<Mutex<Pixels>>,
gui: Gui,
index: usize,
camera: Camera,
rays: Arc<Vec<Ray>>,
}
impl State {
/// Create a new `World` instance that can draw a moving box.
fn new(window: Window, scene: Scene, camera: Camera) -> Self {
fn new(window: Window, scene: Scene) -> Self {
let window_size = window.inner_size();
let pixels = {
let surface_texture =
@@ -65,14 +64,15 @@ impl State {
.unwrap()
};
let gui = Gui::new(&window, &pixels);
let rays = camera.cast_rays(window_size.width, window_size.height);
let rays = scene
.camera
.cast_rays(window_size.width, window_size.height);
Self {
scene: Arc::new(scene),
scene,
window,
pixels: Arc::new(Mutex::new(pixels)),
gui,
camera,
index: 0,
rays: Arc::new(rays),
}
@@ -92,8 +92,8 @@ impl State {
return false;
}
self.index = 0;
self.camera.set_position(self.gui.camera_eye);
self.rays = Arc::new(self.camera.cast_rays(width_new, height_new));
self.scene.camera.set_position(self.gui.camera_eye);
self.rays = Arc::new(self.scene.camera.cast_rays(width_new, height_new));
}
true
}
@@ -201,55 +201,57 @@ impl State {
fn main() -> Result<(), Error> {
env_logger::init();
env::set_var("RUST_BACKTRACE", "1");
Scene::init("test.rhai").expect("Could not read lua file");
//Window
let event_loop = EventLoop::new();
//SCENE
//Camera
let eye = Point3::new(10.0, 0.0, 10.0);
let target = Point3::new(0.0, 0.0, 0.0);
let up = Vector3::new(0.0, 1.0, 0.0);
let camera = Camera::new(
eye,
target,
up,
90.0,
(START_WIDTH as f32 / START_HEIGHT as f32) as f32,
);
// SETUP MATERIALS
let magenta = Arc::new(Material::magenta());
let blue = Arc::new(Material::blue());
let turquoise = Arc::new(Material::turquoise());
let red = Arc::new(Material::red());
// SETUP PRIMITIVES
let mut primitives: Vec<Box<dyn Primitive>> = Vec::new();
//let cube = Box::new(Cube::unit(turquoise.clone()));
// primitives.push(cube);
let sphere = Box::new(Sphere::new(Point3::new(0.0, -2.0, 0.0), 1.0, red.clone()));
let sphere2 = Box::new(Sphere::new(Point3::new(0.0, 2.0, 0.0), 1.0, red.clone()));
let cone = Box::new(Cone::new(1.0, 1.0, -1.0, magenta.clone()));
primitives.push(sphere);
primitives.push(sphere2);
primitives.push(cone);
// SETUP LIGHTS
let light_pos = Point3::new(0.0, 12.0, 4.0);
let light_colour = Vector3::new(0.4, 0.4, 0.6);
let light_falloff = [1.0, 0.00, 0.00];
let light = Light::new(light_colour, light_pos, light_falloff);
let light_pos2 = Point3::new(10.0, 12.0, -4.0);
let light_colour2 = Vector3::new(0.4, 0.0, 0.6);
let light_falloff2 = [1.0, 0.00, 0.00];
let light2 = Light::new(light_colour2, light_pos2, light_falloff2);
let ambient_light = Vector3::new(0.0, 0.0, 0.2);
let scene = Scene::new(
primitives,
vec![light, light2],
vec![camera.clone()],
ambient_light,
);
// //Camera
// let eye = Point3::new(10.0, 0.0, 10.0);
// let target = Point3::new(0.0, 0.0, 0.0);
// let up = Vector3::new(0.0, 1.0, 0.0);
// let camera = Camera::new(
// eye,
// target,
// up,
// 90.0,
// (START_WIDTH as f32 / START_HEIGHT as f32) as f32,
// );
// // SETUP MATERIALS
// let magenta = Arc::new(Material::magenta());
// let blue = Arc::new(Material::blue());
// let turquoise = Arc::new(Material::turquoise());
// let red = Arc::new(Material::red());
// // SETUP PRIMITIVES
// let mut primitives: Vec<Box<dyn Primitive>> = Vec::new();
// //let cube = Box::new(Cube::unit(turquoise.clone()));
// // primitives.push(cube);
// let sphere = Box::new(Sphere::new(Point3::new(0.0, -2.0, 0.0), 1.0, red.clone()));
// let sphere2 = Box::new(Sphere::new(Point3::new(0.0, 2.0, 0.0), 1.0, red.clone()));
// let cone = Box::new(Cone::new(1.0, 1.0, -1.0, magenta.clone()));
// primitives.push(sphere);
// primitives.push(sphere2);
// primitives.push(cone);
//
// // SETUP LIGHTS
// let light_pos = Point3::new(0.0, 12.0, 4.0);
// let light_colour = Vector3::new(0.4, 0.4, 0.6);
// let light_falloff = [1.0, 0.00, 0.00];
// let light = Light::new(light_colour, light_pos, light_falloff);
//
// let light_pos2 = Point3::new(10.0, 12.0, -4.0);
// let light_colour2 = Vector3::new(0.4, 0.0, 0.6);
// let light_falloff2 = [1.0, 0.00, 0.00];
// let light2 = Light::new(light_colour2, light_pos2, light_falloff2);
//
// let ambient_light = Vector3::new(0.0, 0.0, 0.2);
//
// let scene = Scene::new(
// primitives,
// vec![light, light2],
// vec![camera.clone()],
// ambient_light,
// );
//State
let window = {
let size = LogicalSize::new(START_WIDTH, START_HEIGHT);
@@ -260,7 +262,8 @@ fn main() -> Result<(), Error> {
.build(&event_loop)
.unwrap()
};
let mut state = State::new(window, scene, camera);
let scene = Scene::empty();
let mut state = State::new(window, scene);
event_loop.run(move |event, _, control_flow| {
// Draw the current frame
@@ -269,6 +272,7 @@ fn main() -> Result<(), Error> {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
return;
}
WindowEvent::Resized(size) => {
state.resize(&size);

View File

@@ -15,38 +15,38 @@ pub struct Material {
pub shininess: f32,
}
impl Material {
pub fn new(kd: Vector3<f32>, ks: Vector3<f32>, shininess: f32) -> Self {
Material { kd, ks, shininess }
pub fn new(kd: Vector3<f32>, ks: Vector3<f32>, shininess: f32) -> Arc<Self> {
Arc::new(Material { kd, ks, shininess })
}
pub fn magenta() -> Self {
pub fn magenta() -> Arc<Self> {
let kd = Vector3::new(1.0, 0.0, 1.0);
let ks = Vector3::new(1.0, 0.0, 1.0);
let shininess = 0.5;
Material { kd, ks, shininess }
Arc::new(Material { kd, ks, shininess })
}
pub fn turquoise() -> Self {
pub fn turquoise() -> Arc<Self> {
let kd = Vector3::new(0.25, 0.3, 0.7);
let ks = Vector3::new(0.25, 0.3, 0.7);
let shininess = 0.5;
Material { kd, ks, shininess }
Arc::new(Material { kd, ks, shininess })
}
pub fn red() -> Self {
pub fn red() -> Arc<Self> {
let kd = Vector3::new(0.8, 0.0, 0.3);
let ks = Vector3::new(0.8, 0.3, 0.0);
let shininess = 0.5;
Material { kd, ks, shininess }
Arc::new(Material { kd, ks, shininess })
}
pub fn blue() -> Self {
pub fn blue() -> Arc<Self> {
let kd = Vector3::new(0.0, 0.3, 0.6);
let ks = Vector3::new(0.3, 0.0, 0.6);
let shininess = 0.5;
Material { kd, ks, shininess }
Arc::new(Material { kd, ks, shininess })
}
pub fn green() -> Self {
pub fn green() -> Arc<Self> {
let kd = Vector3::new(0.0, 1.0, 0.0);
let ks = Vector3::new(0.0, 1.0, 0.0);
let shininess = 0.5;
Material { kd, ks, shininess }
Arc::new(Material { kd, ks, shininess })
}
}
// INTERSECTION -----------------------------------------------------------------
@@ -122,20 +122,20 @@ pub struct Sphere {
}
impl Sphere {
pub fn new(position: Point3<f32>, radius: f32, material: Arc<Material>) -> Self {
pub fn new(position: Point3<f32>, radius: f32, material: Arc<Material>) -> Arc<dyn Primitive> {
let radius_vec = Vector3::new(radius, radius, radius);
let bln = position - radius_vec;
let trf = position + radius_vec;
let bounding_box = BoundingBox::new(bln, trf);
Sphere {
Arc::new(Sphere {
position,
radius,
bounding_box,
material,
}
})
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material)
}
}
@@ -204,21 +204,21 @@ impl Circle {
radius: f32,
normal: Vector3<f32>,
material: Arc<Material>,
) -> Self {
) -> Arc<dyn Primitive> {
let radius_vec = Vector3::new(radius, radius, radius);
let bln = position - radius_vec;
let trf = position + radius_vec;
let bounding_box = BoundingBox::new(bln, trf);
Circle {
Arc::new(Circle {
position,
radius,
normal: normal.normalize(),
material,
bounding_box,
}
})
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
let position = Point3::new(0.0, 0.0, 0.0);
let normal = Vector3::new(0.0, 1.0, 0.0);
let radius = 1.0;
@@ -228,13 +228,13 @@ impl Circle {
let trf = Point3::new(radius, 0.0, EPSILON);
let bounding_box = BoundingBox { bln, trf };
Circle {
Arc::new(Circle {
position,
normal,
radius,
material,
bounding_box,
}
})
}
}
@@ -303,13 +303,13 @@ pub struct Cone {
radius: f32,
base: f32,
apex: f32,
circle: Circle,
circle: Arc<dyn Primitive>,
material: Arc<Material>,
bounding_box: BoundingBox,
}
impl Cone {
pub fn new(radius: f32, apex: f32, base: f32, material: Arc<Material>) -> Self {
pub fn new(radius: f32, apex: f32, base: f32, material: Arc<Material>) -> Arc<dyn Primitive> {
let circle = Circle::new(
Point3::new(0.0, base, 0.0),
radius,
@@ -318,16 +318,16 @@ impl Cone {
);
let bln = Point3::new(-radius, base, -radius);
let trf = Point3::new(radius, base + apex, radius);
Cone {
Arc::new(Cone {
radius: radius / 2.0,
base,
apex,
circle,
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
Cone::new(1.0, 2.0, -1.0, material)
}
@@ -431,13 +431,13 @@ impl Rectangle {
width: f32,
height: f32,
material: Arc<Material>,
) -> Self {
) -> Arc<dyn Primitive> {
let normal = normal.normalize();
let width_direction = width_direction.normalize();
let height_direction = width_direction.cross(&normal);
let bln = position - width / 2.0 * width_direction - height / 2.0 * height_direction;
let trf = position + width / 2.0 * width_direction + height / 2.0 * height_direction;
Rectangle {
Arc::new(Rectangle {
position,
normal: normal.normalize(),
width_direction: width_direction.normalize(),
@@ -445,9 +445,9 @@ impl Rectangle {
height,
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
Rectangle::new(
Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
@@ -510,18 +510,18 @@ pub struct Cube {
}
impl Cube {
fn new(width: f32, height: f32, depth: f32, material: Arc<Material>) -> Self {
fn new(width: f32, height: f32, depth: f32, material: Arc<Material>) -> Arc<dyn Primitive> {
let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0);
let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0);
Cube {
Arc::new(Cube {
width,
height,
depth,
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
Cube::new(2.0, 2.0, 2.0, material)
}
}
@@ -599,23 +599,28 @@ struct Triangle {
}
impl Triangle {
fn new(u: Point3<f32>, v: Point3<f32>, w: Point3<f32>, material: Arc<Material>) -> Self {
fn new(
u: Point3<f32>,
v: Point3<f32>,
w: Point3<f32>,
material: Arc<Material>,
) -> Arc<dyn Primitive> {
let uv = v - u;
let uw = w - u;
let normal = uv.cross(&uw).normalize();
let bln = u.inf(&v).inf(&w);
let trf = u.sup(&v).sup(&w);
let bounding_box = BoundingBox { bln, trf };
Triangle {
Arc::new(Triangle {
u,
v,
w,
normal,
material,
bounding_box,
})
}
}
pub fn unit(material: Arc<Material>) -> Self {
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> {
let u = Point3::new(-1.0, 0.0, -1.0);
let v = Point3::new(0.0, 0.0, 1.0);
let w = Point3::new(1.0, 0.0, -1.0);
@@ -675,24 +680,24 @@ impl Primitive for Triangle {
// MESH -----------------------------------------------------------------
struct Mesh {
triangles: Vec<Triangle>,
triangles: Vec<Arc<Triangle>>,
material: Arc<Material>,
bounding_box: BoundingBox,
}
impl Mesh {
fn new(triangles: Vec<Triangle>, material: Arc<Material>) -> Self {
fn new(triangles: Vec<Arc<Triangle>>, material: Arc<Material>) -> Arc<dyn Primitive> {
// Calculate the bounding box for the entire mesh based on the bounding boxes of individual triangles
let bounding_box = Mesh::compute_bounding_box(&triangles);
Mesh {
Arc::new(Mesh {
triangles,
material,
bounding_box,
}
})
}
fn compute_bounding_box(triangles: &Vec<Triangle>) -> BoundingBox {
fn compute_bounding_box(triangles: &Vec<Arc<Triangle>>) -> BoundingBox {
let mut bln = Point3::new(INFINITY, INFINITY, INFINITY);
let mut trf = -bln;
for triangle in triangles {
@@ -707,8 +712,8 @@ impl Mesh {
BoundingBox { bln, trf }
}
fn from_file(filename: &str, material: Arc<Material>) -> Self {
let mut triangles: Vec<Triangle> = Vec::new();
fn from_file(filename: &str, material: Arc<Material>) -> Arc<dyn Primitive> {
let mut triangles: Vec<Arc<dyn Primitive>> = Vec::new();
let mut vertices: Vec<Point3<f32>> = Vec::new();
let file = File::open(filename).expect("Failed to open file");

View File

@@ -2,9 +2,10 @@ use crate::{
light::Light,
primitive::{Intersection, Primitive},
ray::Ray,
scene::Scene,
scene::*,
INFINITY,
};
use std::collections::HashMap;
use std::sync::Arc;
use nalgebra::{distance, Matrix4, Point3, Unit, Vector3, Vector4};
@@ -16,7 +17,7 @@ pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Ve
let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize];
for (pixel_index, ray) in rays.iter().enumerate() {
let intersect = get_closest_intersection(&scene.primitives, ray);
let intersect = get_closest_intersection(&scene.nodes, ray);
let colour = match intersect {
Some(intersect) => phong_shade_point(scene, &intersect),
None => {
@@ -30,7 +31,7 @@ pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Ve
}
//Shade a single ray
pub fn shade_ray(scene: &Scene, ray: &Ray) -> Option<Vector3<u8>> {
let intersect = get_closest_intersection(&scene.primitives, ray);
let intersect = get_closest_intersection(&scene.nodes, ray);
match intersect {
Some(intersect) => Some(phong_shade_point(&scene, &intersect)),
None => None,
@@ -38,15 +39,12 @@ pub fn shade_ray(scene: &Scene, ray: &Ray) -> Option<Vector3<u8>> {
}
// Find the closest intersection, given a ray in world coordinates
pub fn get_closest_intersection(
primitives: &Vec<Box<dyn Primitive>>,
ray: &Ray,
) -> Option<Intersection> {
pub fn get_closest_intersection(nodes: &Vec<Node>, ray: &Ray) -> Option<Intersection> {
let mut closest_distance = INFINITY;
let mut closest_intersect: Option<Intersection> = None;
for arc_primitive in primitives {
let primitive = arc_primitive.clone();
for node in nodes {
let primitive = node.primitive.clone();
if let Some(intersect) = primitive.intersect_ray(ray) {
if intersect.distance < closest_distance {
@@ -70,8 +68,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
material,
..
} = intersect;
let binding = scene.ambient_light.clone();
let ambient_light = binding.as_ref();
let ambient_light = &scene.ambient_light;
let kd = material.kd;
let ks = material.ks;
let shininess = material.shininess;
@@ -80,9 +77,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
// Let us first compute the ambient light component and set it as out base colour
let mut colour = kd.component_mul(ambient_light);
for arc_light in scene.lights.as_ref() {
let light = arc_light.clone();
for light in &scene.lights {
let Light {
position: light_position,
colour: light_colour,

View File

@@ -1,29 +1,129 @@
use crate::camera::Camera;
use crate::light::Light;
use crate::primitive::Primitive;
use nalgebra::Vector3;
use crate::primitive::*;
use nalgebra::{Matrix4, Point3, Vector3};
use rhai::{Engine, EvalAltResult};
use std::collections::HashMap;
use std::sync::Arc;
const LIGHT_AMBIENT: f32 = 0.2;
#[derive(Clone)]
pub struct Node {
pub primitive: Arc<dyn Primitive>,
pub model_transform: Matrix4<f32>,
}
impl Node {
pub fn new(primitive: Arc<dyn Primitive>) -> Self {
Node {
primitive,
model_transform: Matrix4::identity(),
}
}
pub fn rotate(&mut self, roll: f32, pitch: f32, yaw: f32) {
let roll = (roll as f64).to_radians() as f32;
let pitch = (pitch as f64).to_radians() as f32;
let yaw = (yaw as f64).to_radians() as f32;
let rotation_matrix = Matrix4::from_euler_angles(roll, pitch, yaw);
self.model_transform = rotation_matrix * self.model_transform;
}
pub fn translate(&mut self, translation: &Vector3<f32>) {
let translation_matrix = Matrix4::new_translation(translation);
self.model_transform = translation_matrix * self.model_transform;
}
pub fn scale(&mut self, scale: &Vector3<f32>) {
let scale_matrix = Matrix4::new_nonuniform_scaling(scale);
self.model_transform = scale_matrix * self.model_transform;
}
}
#[derive(Clone)]
pub struct Scene {
pub primitives: Arc<Vec<Box<dyn Primitive>>>,
pub lights: Arc<Vec<Light>>,
pub cameras: Arc<Vec<Camera>>,
pub ambient_light: Arc<Vector3<f32>>,
pub nodes: Vec<Node>,
pub materials: Vec<Material>,
pub lights: Vec<Light>,
pub cameras: Vec<Camera>,
pub ambient_light: Vector3<f32>,
pub camera: Camera,
}
impl Scene {
// Creates a scene
pub fn new(
primitives: Vec<Box<dyn Primitive>>,
lights: Vec<Light>,
cameras: Vec<Camera>,
ambient_light: Vector3<f32>,
) -> Self {
// Creates an emptry scene
pub fn empty() -> Self {
Scene {
primitives: Arc::new(primitives),
lights: Arc::new(lights),
cameras: Arc::new(cameras),
ambient_light: Arc::new(ambient_light),
nodes: Vec::new(),
materials: Vec::new(),
lights: Vec::new(),
cameras: Vec::new(),
camera: Camera::new(
Point3::new(0.0, 0.0, -10.0),
Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, 0.0, -1.0),
120.0,
1.0,
),
ambient_light: Vector3::new(LIGHT_AMBIENT, LIGHT_AMBIENT, LIGHT_AMBIENT),
}
}
fn add_node(&mut self, node: Node) {
self.nodes.push(node);
}
fn add_material(&mut self, material: Material) {
self.materials.push(material);
}
fn add_light(&mut self, light: Light) {
self.lights.push(light);
}
fn add_camera(&mut self, camera: Camera) {
self.cameras.push(camera);
}
fn set_ambient(&mut self, intensity: Vector3<f32>) {
self.ambient_light = intensity;
}
fn set_camera(&mut self, camera: Camera) {
self.camera = camera;
}
fn get_camera(&self) -> &Camera {
&self.camera
}
fn get_ambient(&self) -> Arc<Vector3<f32>> {
Arc::new(self.ambient_light)
}
pub fn init(filename: &str) -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
engine
.register_type::<Vector3<f32>>()
.register_fn("V", Vector3::<f32>::new);
engine
.register_type::<Point3<f32>>()
.register_fn("P", Point3::<f32>::new);
engine
.register_type::<Scene>()
.register_fn("Scene", Scene::empty)
.register_fn("addNode", Scene::add_node);
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);
engine
.register_type::<Light>()
.register_fn("Light", Light::new);
engine
.register_type::<Material>()
.register_fn("Material", Material::new);
engine
.register_type::<Sphere>()
.register_fn("Sphere", Sphere::new);
engine.run_file(filename.into())?;
Ok(())
}
}