slight refactor (2)
This commit is contained in:
parent
00000330fe
commit
0000034060
6 changed files with 94 additions and 87 deletions
|
@ -13,8 +13,6 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
|
||||||
use scene::data::ObjectKind;
|
|
||||||
use scene::Scene;
|
use scene::Scene;
|
||||||
|
|
||||||
use crate::image::Image;
|
use crate::image::Image;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ordered_float::NotNan;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::utils::compute_rotation_matrix;
|
use crate::utils::compute_rotation_matrix;
|
||||||
|
|
||||||
use super::data::{IntersectionContext, ObjectKind};
|
use super::{data::ObjectKind, illumination::IntersectionContext};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cylinder {
|
pub struct Cylinder {
|
||||||
|
|
|
@ -2,12 +2,12 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
use crate::image::Color;
|
use crate::image::Color;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
|
|
||||||
use super::Scene;
|
use super::Scene;
|
||||||
|
use super::illumination::IntersectionContext;
|
||||||
|
|
||||||
pub trait ObjectKind: Debug + Send + Sync {
|
pub trait ObjectKind: Debug + Send + Sync {
|
||||||
/// Determine where the ray intersects this object, returning the earliest
|
/// Determine where the ray intersects this object, returning the earliest
|
||||||
|
@ -74,89 +74,7 @@ pub struct DepthCueing {
|
||||||
dist_min: f64,
|
dist_min: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about an intersection
|
|
||||||
#[derive(Derivative)]
|
|
||||||
#[derivative(Debug, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub struct IntersectionContext {
|
|
||||||
/// The time of the intersection in the parametric ray
|
|
||||||
///
|
|
||||||
/// Unfortunately, IEEE floats in Rust don't have total ordering, because
|
|
||||||
/// NaNs violate ordering properties. The way to remedy this is to ensure we
|
|
||||||
/// don't have NaNs by wrapping it into this type, which then implements
|
|
||||||
/// total ordering.
|
|
||||||
pub time: NotNan<f64>,
|
|
||||||
|
|
||||||
/// The intersection point.
|
|
||||||
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
|
||||||
pub point: Vector3<f64>,
|
|
||||||
|
|
||||||
/// The normal vector protruding from the surface of the object at the
|
|
||||||
/// intersection point
|
|
||||||
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
|
||||||
pub normal: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for IntersectionContext {}
|
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
/// Determine the color that should be used to fill this pixel.
|
|
||||||
///
|
|
||||||
/// - material_idx is the index into the materials list.
|
|
||||||
/// - intersection_context contains information on vectors where the
|
|
||||||
/// intersection occurred
|
|
||||||
///
|
|
||||||
/// Also known as Shade_Ray in the slides.
|
|
||||||
pub fn compute_pixel_color(
|
|
||||||
&self,
|
|
||||||
material_idx: usize,
|
|
||||||
intersection_context: IntersectionContext,
|
|
||||||
) -> Color {
|
|
||||||
// TODO: Does it make sense to make this function fallible from an API
|
|
||||||
// design standpoint?
|
|
||||||
let material = match self.materials.get(material_idx) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return self.bkg_color,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ambient_component = material.k_a * material.diffuse_color;
|
|
||||||
|
|
||||||
// Diffuse and specular lighting for each separate light
|
|
||||||
let diffuse_and_specular: Vector3<f64> = self
|
|
||||||
.lights
|
|
||||||
.iter()
|
|
||||||
.map(|light| {
|
|
||||||
// The vector pointing in the direction of the light
|
|
||||||
let light_direction = match light.kind {
|
|
||||||
LightKind::Point { location } => {
|
|
||||||
location - intersection_context.point
|
|
||||||
}
|
|
||||||
LightKind::Directional { direction } => direction,
|
|
||||||
}
|
|
||||||
.normalize();
|
|
||||||
|
|
||||||
let normal = intersection_context.normal.normalize();
|
|
||||||
let viewer_direction = self.eye_pos - intersection_context.point;
|
|
||||||
let halfway_direction =
|
|
||||||
((light_direction + viewer_direction) / 2.0).normalize();
|
|
||||||
|
|
||||||
let diffuse_component = material.k_d
|
|
||||||
* material.diffuse_color
|
|
||||||
* normal.dot(&light_direction).max(0.0);
|
|
||||||
|
|
||||||
let specular_component = material.k_s
|
|
||||||
* material.specular_color
|
|
||||||
* normal
|
|
||||||
.dot(&halfway_direction)
|
|
||||||
.max(0.0)
|
|
||||||
.powf(material.exponent);
|
|
||||||
|
|
||||||
diffuse_component + specular_component
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
ambient_component + diffuse_and_specular
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determine the boundaries of the viewing window in world coordinates
|
/// Determine the boundaries of the viewing window in world coordinates
|
||||||
pub fn compute_viewing_window(&self, distance: f64) -> Rect {
|
pub fn compute_viewing_window(&self, distance: f64) -> Rect {
|
||||||
// Compute viewing directions
|
// Compute viewing directions
|
||||||
|
|
90
assignment-1b/src/scene/illumination.rs
Normal file
90
assignment-1b/src/scene/illumination.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
|
use crate::image::Color;
|
||||||
|
|
||||||
|
use super::{Scene, data::LightKind};
|
||||||
|
|
||||||
|
/// Information about an intersection
|
||||||
|
#[derive(Derivative)]
|
||||||
|
#[derivative(Debug, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct IntersectionContext {
|
||||||
|
/// The time of the intersection in the parametric ray
|
||||||
|
///
|
||||||
|
/// Unfortunately, IEEE floats in Rust don't have total ordering, because
|
||||||
|
/// NaNs violate ordering properties. The way to remedy this is to ensure we
|
||||||
|
/// don't have NaNs by wrapping it into this type, which then implements
|
||||||
|
/// total ordering.
|
||||||
|
pub time: NotNan<f64>,
|
||||||
|
|
||||||
|
/// The intersection point.
|
||||||
|
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
||||||
|
pub point: Vector3<f64>,
|
||||||
|
|
||||||
|
/// The normal vector protruding from the surface of the object at the
|
||||||
|
/// intersection point
|
||||||
|
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
||||||
|
pub normal: Vector3<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for IntersectionContext {}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
/// Determine the color that should be used to fill this pixel.
|
||||||
|
///
|
||||||
|
/// - material_idx is the index into the materials list.
|
||||||
|
/// - intersection_context contains information on vectors where the
|
||||||
|
/// intersection occurred
|
||||||
|
///
|
||||||
|
/// Also known as Shade_Ray in the slides.
|
||||||
|
pub fn compute_pixel_color(
|
||||||
|
&self,
|
||||||
|
material_idx: usize,
|
||||||
|
intersection_context: IntersectionContext,
|
||||||
|
) -> Color {
|
||||||
|
// TODO: Does it make sense to make this function fallible from an API
|
||||||
|
// design standpoint?
|
||||||
|
let material = match self.materials.get(material_idx) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return self.bkg_color,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ambient_component = material.k_a * material.diffuse_color;
|
||||||
|
|
||||||
|
// Diffuse and specular lighting for each separate light
|
||||||
|
let diffuse_and_specular: Vector3<f64> = self
|
||||||
|
.lights
|
||||||
|
.iter()
|
||||||
|
.map(|light| {
|
||||||
|
// The vector pointing in the direction of the light
|
||||||
|
let light_direction = match light.kind {
|
||||||
|
LightKind::Point { location } => {
|
||||||
|
location - intersection_context.point
|
||||||
|
}
|
||||||
|
LightKind::Directional { direction } => direction,
|
||||||
|
}
|
||||||
|
.normalize();
|
||||||
|
|
||||||
|
let normal = intersection_context.normal.normalize();
|
||||||
|
let viewer_direction = self.eye_pos - intersection_context.point;
|
||||||
|
let halfway_direction =
|
||||||
|
((light_direction + viewer_direction) / 2.0).normalize();
|
||||||
|
|
||||||
|
let diffuse_component = material.k_d
|
||||||
|
* material.diffuse_color
|
||||||
|
* normal.dot(&light_direction).max(0.0);
|
||||||
|
|
||||||
|
let specular_component = material.k_s
|
||||||
|
* material.specular_color
|
||||||
|
* normal
|
||||||
|
.dot(&halfway_direction)
|
||||||
|
.max(0.0)
|
||||||
|
.powf(material.exponent);
|
||||||
|
|
||||||
|
diffuse_component + specular_component
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
ambient_component + diffuse_and_specular
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ pub mod cylinder;
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod input_file;
|
pub mod input_file;
|
||||||
pub mod sphere;
|
pub mod sphere;
|
||||||
|
pub mod illumination;
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ordered_float::NotNan;
|
||||||
|
|
||||||
use crate::{ray::Ray, utils::min_f64};
|
use crate::{ray::Ray, utils::min_f64};
|
||||||
|
|
||||||
use super::data::{IntersectionContext, ObjectKind};
|
use super::{data::ObjectKind, illumination::IntersectionContext};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
|
|
Loading…
Reference in a new issue