Added reflection material

This commit is contained in:
STP
2023-11-28 23:26:29 -05:00
parent e756a001e9
commit 076498b3c6
2 changed files with 74 additions and 40 deletions

View File

@@ -5,6 +5,7 @@ use nalgebra::Vector3;
pub struct Material { pub struct Material {
pub kd: Vector3<f32>, pub kd: Vector3<f32>,
pub ks: Vector3<f32>, pub ks: Vector3<f32>,
pub kr: Vector3<f32>,
pub shininess: f32, pub shininess: f32,
} }
@@ -12,37 +13,73 @@ impl Material {
pub fn new(kd: Vector3<f64>, ks: Vector3<f64>, shininess: f64) -> Material { pub fn new(kd: Vector3<f64>, ks: Vector3<f64>, shininess: f64) -> Material {
let kd = kd.cast(); let kd = kd.cast();
let ks = ks.cast(); let ks = ks.cast();
let kr = ks.cast();
let shininess = shininess as f32; let shininess = shininess as f32;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
pub fn magenta() -> Material { pub fn magenta() -> Material {
let kd = Vector3::new(1.0, 0.0, 1.0); let kd = Vector3::new(1.0, 0.0, 1.0);
let ks = Vector3::new(1.0, 0.0, 1.0); let ks = Vector3::new(1.0, 0.0, 1.0);
let kr = Vector3::new(0.0, 0.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
pub fn turquoise() -> Material { pub fn turquoise() -> Material {
let kd = Vector3::new(0.25, 0.3, 0.7); let kd = Vector3::new(0.25, 0.3, 0.7);
let ks = Vector3::new(0.25, 0.3, 0.7); let ks = Vector3::new(0.25, 0.3, 0.7);
let kr = Vector3::new(0.0, 0.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
pub fn red() -> Material { pub fn red() -> Material {
let kd = Vector3::new(0.8, 0.0, 0.3); let kd = Vector3::new(0.8, 0.0, 0.3);
let ks = Vector3::new(0.8, 0.3, 0.0); let ks = Vector3::new(0.8, 0.3, 0.0);
let kr = Vector3::new(0.0, 0.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
pub fn blue() -> Material { pub fn blue() -> Material {
let kd = Vector3::new(0.0, 0.3, 0.6); let kd = Vector3::new(0.0, 0.3, 0.6);
let ks = Vector3::new(0.3, 0.0, 0.6); let ks = Vector3::new(0.3, 0.0, 0.6);
let kr = Vector3::new(0.0, 0.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
pub fn green() -> Material { pub fn green() -> Material {
let kd = Vector3::new(0.0, 1.0, 0.0); let kd = Vector3::new(0.0, 1.0, 0.0);
let ks = Vector3::new(0.0, 1.0, 0.0); let ks = Vector3::new(0.0, 1.0, 0.0);
let kr = Vector3::new(0.0, 0.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Material { kd, ks, shininess } Material {
kd,
ks,
kr,
shininess,
}
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::{node::Node, scene::Scene}; use crate::{node::Node, scene::Scene, EPSILON};
use nalgebra::{Matrix4, Point3, Vector3}; use nalgebra::{distance, Matrix4, Point3, Vector3};
use rand; use rand;
const MAX_DEPTH: u8 = 5; const MAX_DEPTH: u8 = 5;
@@ -12,13 +12,6 @@ fn random_vec() -> Vector3<f64> {
fn random_unit_vec() -> Vector3<f64> { fn random_unit_vec() -> Vector3<f64> {
random_vec().normalize() random_vec().normalize()
} }
fn random_on_hemisphere(normal: &Vector3<f64>) -> Vector3<f64> {
let dir = random_unit_vec();
match dir.dot(normal) > 0.0 {
true => dir,
false => -dir,
}
}
// INTERSECTION ----------------------------------------------------------------- // INTERSECTION -----------------------------------------------------------------
pub struct Intersection { pub struct Intersection {
@@ -105,20 +98,17 @@ impl Ray {
if node.primitive.intersect_bounding_box(&ray) { if node.primitive.intersect_bounding_box(&ray) {
// Check primitive intersection // Check primitive intersection
if let Some(intersect) = node.primitive.intersect_ray(&ray) { if let Some(intersect) = node.primitive.intersect_ray(&ray) {
// Check for closest distance // Check for closest distance by converting to world coords
if intersect.distance < closest_distance { let intersect = intersect.transform(&node.model, &node.inv_model);
closest_distance = intersect.distance; let distance = distance(&ray.a, &intersect.point);
if distance < closest_distance {
closest_distance = distance;
closest_intersect = Some((node, intersect)); closest_intersect = Some((node, intersect));
} }
} }
} }
} }
match closest_intersect { closest_intersect
Some((node, intersect)) => {
Some((node, intersect.transform(&node.model, &node.inv_model)))
}
None => None,
}
} }
// This function takes a scene and returns the color of the point where the ray intersects the scene // This function takes a scene and returns the color of the point where the ray intersects the scene
pub fn shade_ray(&self, scene: &Scene, depth: u8) -> Option<Vector3<f32>> { pub fn shade_ray(&self, scene: &Scene, depth: u8) -> Option<Vector3<f32>> {
@@ -143,8 +133,8 @@ impl Ray {
intersect: &Intersection, intersect: &Intersection,
depth: u8, depth: u8,
) -> Vector3<f32> { ) -> Vector3<f32> {
let point = &intersect.point;
let normal = &intersect.normal; let normal = &intersect.normal;
let point = intersect.point + EPSILON * normal;
let incidence = &ray.b; let incidence = &ray.b;
let material = &node.material; let material = &node.material;
@@ -166,42 +156,49 @@ impl Ray {
let light_distance = to_light.norm() as f32; let light_distance = to_light.norm() as f32;
let to_light = to_light.normalize(); let to_light = to_light.normalize();
let to_light_ray = Ray::new(point.clone() + 0.001 * normal, to_light); //Niave Shadows
let to_light_ray = Ray::new(point, to_light);
if to_light_ray.light_blocked(scene, node) { if to_light_ray.light_blocked(scene, node) {
continue; continue;
} }
let n_dot_l = normal.dot(&to_light).max(0.0) as f32; let n_dot_l = normal.dot(&to_light).max(0.0) as f32;
//Diffuse component //Reflected component
let mut reflect = Vector3::zeros();
let reflect_dir = incidence - 2.0 * incidence.dot(&normal) * normal;
let reflect_ray = Ray::new(point, reflect_dir);
if let Some(col) = reflect_ray.shade_ray(scene, depth + 1) {
reflect += col.component_mul(&material.kr)
}
//Diffuse component (Lambertian)
let mut diffuse = Vector3::zeros(); let mut diffuse = Vector3::zeros();
// diffuse = material.kd * n_dot_l; diffuse += material.kd * n_dot_l;
for _ in 0..DIFFUSE_RAYS { for _ in 0..DIFFUSE_RAYS {
let diffuse_dir = random_on_hemisphere(normal); let diffuse_dir = random_unit_vec();
let ray = Ray::new(point.clone() + normal, diffuse_dir); let diffuse_ray = Ray::new(point.clone(), diffuse_dir + normal);
if let Some(col) = ray.shade_ray(scene, depth + 1) { if let Some(col) = diffuse_ray.shade_ray(scene, depth + 1) {
diffuse += col * DIFFUSE_COEFFICIENT; diffuse += col * DIFFUSE_COEFFICIENT;
} }
} }
//Specular component //Specular component
let mut specular = Vector3::zeros(); let mut specular = Vector3::zeros();
if n_dot_l > 0.0 { if n_dot_l < 0.0 {
let h = (to_light - incidence).normalize(); let h = (to_light - incidence).normalize();
let n_dot_h = normal.dot(&h).max(0.0) as f32; let n_dot_h = normal.dot(&h).max(0.0) as f32;
specular = material.ks * n_dot_h.powf(material.shininess); specular = material.ks * n_dot_h.powf(material.shininess);
} }
//Falloff //Falloff
let falloff = 1.0 // let falloff = 1.0
/ (1.0 // / (1.0
+ light.falloff[0] // + light.falloff[0]
+ light.falloff[1] * light_distance // + light.falloff[1] * light_distance
+ light.falloff[2] * light_distance * light_distance); // + light.falloff[2] * light_distance * light_distance);
let intensity = light let intensity = light.colour.component_mul(&(diffuse + reflect + specular));
.colour
.component_mul(&((diffuse + specular) * falloff));
colour += &intensity; colour += &intensity;
} }