Added scene, raytracer, pixel display and lights
This commit is contained in:
79
src/display.rs
Normal file
79
src/display.rs
Normal file
@@ -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();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
23
src/light.rs
Normal file
23
src/light.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use nalgebra::{Point3, Vector3};
|
||||
|
||||
pub struct Light {
|
||||
pub colour: Vector3<f32>,
|
||||
pub position: Point3<f32>,
|
||||
pub falloff: [f32; 3],
|
||||
}
|
||||
|
||||
impl Light {
|
||||
pub fn new(colour: Vector3<f32>, position: Point3<f32>, 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)
|
||||
}
|
||||
}
|
||||
52
src/raytracer.rs
Normal file
52
src/raytracer.rs
Normal file
@@ -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<Intersection<'a>> {
|
||||
let mut closest_distance = INFINITY;
|
||||
let mut closest_intersect: Option<Intersection> = 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<Vector4<f32>> {
|
||||
//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
|
||||
}
|
||||
13
src/scene.rs
Normal file
13
src/scene.rs
Normal file
@@ -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<Box<dyn Primitive<'a>>>,
|
||||
lights: Vec<Light>,
|
||||
camera: Camera,
|
||||
pub ambient_light: Vector3<f32>,
|
||||
}
|
||||
|
||||
impl<'a> Scene<'a> {}
|
||||
Reference in New Issue
Block a user