From 2c65a48cb23d13ba66cb96d875be640586938a46 Mon Sep 17 00:00:00 2001 From: STP Date: Mon, 13 Nov 2023 00:42:23 -0500 Subject: [PATCH] Added scene, raytracer, pixel display and lights --- src/display.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ src/light.rs | 23 ++++++++++++++ src/raytracer.rs | 52 +++++++++++++++++++++++++++++++ src/scene.rs | 13 ++++++++ 4 files changed, 167 insertions(+) create mode 100644 src/display.rs create mode 100644 src/light.rs create mode 100644 src/raytracer.rs create mode 100644 src/scene.rs diff --git a/src/display.rs b/src/display.rs new file mode 100644 index 0000000..4df2c8f --- /dev/null +++ b/src/display.rs @@ -0,0 +1,79 @@ +use pixels::{Error, Pixels, SurfaceTexture}; + +use std::time::Instant; + +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; + +pub fn run() -> Result<(), Error> { + // Create an event loop and window using winit + let event_loop = EventLoop::new(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); + + // Create a Pixels instance for drawing + let mut pixels = { + let window_size = window.inner_size(); + let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window); + Pixels::new(800, 600, surface_texture).unwrap() + }; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + match event { + Event::WindowEvent { + ref event, + window_id, + } if window_id == window.id() => { + match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::Resized(physical_size) => { + //We want to change the size of the pixel display + pixels + .resize_surface(physical_size.width, physical_size.height) + .expect("Could not resize"); + pixels + .resize_buffer(physical_size.width, physical_size.height) + .expect("Could not resize"); + } + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + //We want to change the size of the pixel display + // new_inner_size is &mut so w have to dereference it twice + pixels + .resize_surface(new_inner_size.width, new_inner_size.height) + .expect("Could not resize!"); + pixels + .resize_buffer(new_inner_size.width, new_inner_size.height) + .expect("Could not resize"); + } + WindowEvent::KeyboardInput { input, .. } => { + println!("Key input: {}", input.scancode); + } + _ => {} + } + } + Event::RedrawRequested(_) => { + // Draw a pixel at every coordinate + for (i, pixel) in pixels.frame_mut().chunks_exact_mut(4).enumerate() { + let r = (i as u8).wrapping_mul(50); + let g = 43; + let b = 3; + let a = 255; + pixel.copy_from_slice(&[r, g, b, a]); + } + // Render the frame + if pixels.render().is_err() { + eprintln!("Failed to render frame"); + } + } + Event::MainEventsCleared => { + // RedrawRequested will only trigger once, unless we manually + // request it. + window.request_redraw(); + } + _ => {} + } + }); +} diff --git a/src/light.rs b/src/light.rs new file mode 100644 index 0000000..43a1c83 --- /dev/null +++ b/src/light.rs @@ -0,0 +1,23 @@ +use nalgebra::{Point3, Vector3}; + +pub struct Light { + pub colour: Vector3, + pub position: Point3, + pub falloff: [f32; 3], +} + +impl Light { + pub fn new(colour: Vector3, position: Point3, falloff: [f32; 3]) -> Self { + Light { + colour, + position, + falloff, + } + } + pub fn white() -> Self { + let colour = Vector3::new(1.0, 1.0, 1.0); + let position = Point3::new(0.0, 0.0, 0.0); + let falloff = [1.0, 0.0, 0.0]; + Light::new(colour, position, falloff) + } +} diff --git a/src/raytracer.rs b/src/raytracer.rs new file mode 100644 index 0000000..90ba6c1 --- /dev/null +++ b/src/raytracer.rs @@ -0,0 +1,52 @@ +use crate::{ + primitive::{Intersection, Primitive}, + ray::Ray, + scene::Scene, + INFINITY, +}; +use nalgebra::{distance, Matrix4, Point3, Vector3, Vector4}; + +// Find the closest intersection, given a ray in world coordinates +fn get_closest_intersection<'a>(scene: &'a Scene, ray: &Ray) -> Option> { + let mut closest_distance = INFINITY; + let mut closest_intersect: Option = None; + for primitive in &scene.primitives { + if primitive.intersect_bounding_box(ray) == None { + continue; + }; + + let intersect = primitive.intersect_ray(ray); + if intersect.is_none() { + continue; + }; + + let intersect = intersect.unwrap(); + if intersect.distance < closest_distance { + closest_distance = intersect.distance; + closest_intersect = Some(intersect); + } + } + closest_intersect +} + +// We want to shade a point placed in our scene +fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Option> { + //Unpack the intersection data + let Intersection { + primitive, + point, + normal, + incidence, + distance, + } = intersect; + let ambient_light = scene.ambient_light; + let material = primitive.get_material(); + let kd = material.kd; + let ks = material.kd; + let shininess = material.shininess; + // We should now have all the information for our ray-tracer + + // Let us first compute the ambient light component + let ambient = ambient_light * kd; + None +} diff --git a/src/scene.rs b/src/scene.rs new file mode 100644 index 0000000..8b0f373 --- /dev/null +++ b/src/scene.rs @@ -0,0 +1,13 @@ +use crate::camera::Camera; +use crate::light::Light; +use crate::primitive::Primitive; +use nalgebra::Vector3; + +pub struct Scene<'a> { + pub primitives: Vec>>, + lights: Vec, + camera: Camera, + pub ambient_light: Vector3, +} + +impl<'a> Scene<'a> {}