Refactor into real project structure
This commit is contained in:
188
src/renderer.rs
Normal file
188
src/renderer.rs
Normal file
@@ -0,0 +1,188 @@
|
||||
// renderer.rs
|
||||
|
||||
use std::f32;
|
||||
use nalgebra::*;
|
||||
use std::ops::{Add,Mul};
|
||||
|
||||
use crate::camera::*;
|
||||
|
||||
use crate::elements::{Element,Intersectable};
|
||||
use crate::materials::SurfaceType;
|
||||
|
||||
const BLACK: Color = Color {
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.0,
|
||||
};
|
||||
|
||||
pub struct Ray {
|
||||
pub pos: Vec3<f64>,
|
||||
pub dir: Vec3<f64>
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
fn new(pos: Vec3<f64>, dir: Vec3<f64>) -> Ray {
|
||||
Ray {
|
||||
pos: pos,
|
||||
dir: dir
|
||||
}
|
||||
}
|
||||
|
||||
fn at(&self, t: f64) -> Vec3<f64> {
|
||||
self.pos + t * self.dir
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Color {
|
||||
pub red: f32,
|
||||
pub green: f32,
|
||||
pub blue: f32,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(red: f32, green: f32, blue: f32) -> Color {
|
||||
Color {
|
||||
red: red,
|
||||
green: green,
|
||||
blue: blue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Color {
|
||||
type Output = Color;
|
||||
|
||||
fn mul(self, other: Color) -> Color {
|
||||
Color {
|
||||
red: self.red * other.red,
|
||||
green: self.green * other.green,
|
||||
blue: self.blue * other.blue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Color {
|
||||
type Output = Color;
|
||||
|
||||
fn mul(self, other: f32) -> Color {
|
||||
Color {
|
||||
red: self.red * other,
|
||||
green: self.green * other,
|
||||
blue: self.blue * other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Color {
|
||||
type Output = Color;
|
||||
|
||||
fn add(self, other: Color) -> Color {
|
||||
Color {
|
||||
red: self.red + other.red,
|
||||
green: self.green + other.green,
|
||||
blue: self.blue + other.blue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Color> for f32 {
|
||||
type Output = Color;
|
||||
|
||||
fn mul(self, other: Color) -> Color {
|
||||
other * self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Intersection<'a> {
|
||||
pub distance: f64,
|
||||
pub object: &'a Element
|
||||
}
|
||||
|
||||
impl<'a> Intersection<'a> {
|
||||
pub fn new<'b>(distance: f64, object: &'b Element) -> Intersection<'b> {
|
||||
Intersection {
|
||||
distance: distance,
|
||||
object: & object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Intersectable for Element {
|
||||
fn intersect(&self, ray: &Ray) -> Option<f64> {
|
||||
match *self {
|
||||
Element::Sphere(ref s) => s.intersect(ray),
|
||||
Element::Plane(ref p) => p.intersect(ray),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn create_reflection(normal: Vec3<f64>, incident: Vec3<f64>, hit_point: Vec3<f64>, bias: f64) -> Ray {
|
||||
Ray {
|
||||
pos: hit_point + (normal.normalize()),
|
||||
dir: incident - (2.0 * incident.dot(&normal) * normal),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_color(camera: &PerspectiveCamera, ray: &Ray, intersection: &Intersection, depth: u32) -> Color {
|
||||
let hit_point = ray.pos + (ray.dir * intersection.distance);
|
||||
let surface_normal = intersection.object.normal(hit_point);
|
||||
|
||||
let material = intersection.object.material();
|
||||
|
||||
let mut color = shade_diffuse(camera, intersection.object, hit_point, surface_normal);
|
||||
|
||||
if let SurfaceType::Reflective { reflectivity } = material.surface {
|
||||
let reflection_ray = create_reflection(surface_normal, ray.dir, hit_point, camera.shadow_bias);
|
||||
color = color * (1.0 - reflectivity);
|
||||
color = color + (cast_ray(&camera, &reflection_ray, depth + 1) * reflectivity);
|
||||
}
|
||||
color
|
||||
}
|
||||
|
||||
fn shade_diffuse(camera: &PerspectiveCamera, object: &Element, hit_point: Vec3<f64>, surface_normal: Vec3<f64>) -> Color {
|
||||
let mut color = BLACK;
|
||||
|
||||
// Light processing
|
||||
// TODO: Support multiple lights
|
||||
for light in camera.lights.iter() {
|
||||
let direction_to_light = light.pos - hit_point;
|
||||
|
||||
let material = object.material();
|
||||
// TODO: Change light intensity to take hit_point for some reason (read source)
|
||||
// https://github.com/bheisler/raytracer/blob/7130556181de7fc59eaa29346f5d4134db3e720e/src/rendering.rs#L195
|
||||
|
||||
// Shadow stuff
|
||||
let shadow_ray = Ray {
|
||||
pos: hit_point + surface_normal.normalize(),
|
||||
dir: direction_to_light.normalize(),
|
||||
};
|
||||
|
||||
let shadow_intersection = camera.trace(&shadow_ray);
|
||||
let in_light = shadow_intersection.is_none()
|
||||
|| shadow_intersection.unwrap().distance > light.distance(hit_point);
|
||||
let light_intensity = if in_light { light.intensity } else { 0.0 };
|
||||
|
||||
let light_power = (surface_normal.normalize().dot(&direction_to_light.normalize()) as f32).max(0.0);
|
||||
let light_reflected = material.albedo / f32::consts::PI;
|
||||
|
||||
let light_color = light_intensity * light_power * light_reflected;
|
||||
color = color + (material.coloration * light_color);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
pub fn cast_ray(camera: &PerspectiveCamera, ray: &Ray, depth: u32) -> Color {
|
||||
if depth >= camera.max_recursion_depth {
|
||||
return BLACK;
|
||||
}
|
||||
|
||||
let intersection = camera.trace(&ray);
|
||||
intersection.map(|i| get_color(camera, &ray, &i, depth)).unwrap_or(BLACK)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user