Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2024-03-02 #200

Merged
merged 2 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clovers/benches/aabb.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::f32::{INFINITY, NEG_INFINITY};

use clovers::interval::Interval;
use clovers::random::random_unit_vector;
use clovers::ray::Ray;
use clovers::wavelength::random_wavelength;
use clovers::{aabb::*, Vec3};
Expand Down Expand Up @@ -81,7 +82,7 @@ fn random_aabb(rng: &mut SmallRng) -> AABB {
fn random_ray(rng: &mut SmallRng) -> Ray {
black_box(Ray {
origin: Vec3::new(0.0, 0.0, 0.0),
direction: Vec3::new(rng.gen(), rng.gen(), rng.gen()),
direction: random_unit_vector(rng),
time: rng.gen(),
wavelength: random_wavelength(rng),
})
Expand Down
3 changes: 2 additions & 1 deletion clovers/benches/triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::f32::{INFINITY, NEG_INFINITY};
use clovers::hitable::HitableTrait;
use clovers::materials::Material;
use clovers::objects::Triangle;
use clovers::random::random_unit_vector;
use clovers::ray::Ray;
use clovers::wavelength::random_wavelength;
use clovers::Vec3;
Expand Down Expand Up @@ -71,7 +72,7 @@ fn random_ray() -> Ray {
let mut rng = SmallRng::from_entropy();
black_box(Ray {
origin: Vec3::new(0.0, 0.0, 0.0),
direction: Vec3::new(rng.gen(), rng.gen(), rng.gen()),
direction: random_unit_vector(&mut rng),
time: rng.gen(),
wavelength: random_wavelength(&mut rng),
})
Expand Down
4 changes: 2 additions & 2 deletions clovers/src/aabb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use core::ops::Add;

use crate::{interval::Interval, ray::Ray, Float, Vec3, EPSILON_RECT_THICKNESS};
use crate::{interval::Interval, ray::Ray, Float, Position, Vec3, EPSILON_RECT_THICKNESS};

/// Axis-aligned bounding box Defined by two opposing corners, each of which are a [Vec3].
///
Expand Down Expand Up @@ -31,7 +31,7 @@ impl AABB {

/// Creates a new axis-aligned bounding box from two coordinates. Treats the two points a and b as extrema for the bounding box, so we don't require a particular minimum/maximum coordinate order.
#[must_use]
pub fn new_from_coords(a: Vec3, b: Vec3) -> AABB {
pub fn new_from_coords(a: Position, b: Position) -> AABB {
AABB {
x: Interval::new(a[0].min(b[0]), a[0].max(b[0])),
y: Interval::new(a[1].min(b[1]), a[1].max(b[1])),
Expand Down
24 changes: 16 additions & 8 deletions clovers/src/bvhnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
hitable::{Empty, HitRecord, Hitable, HitableTrait},
ray::Ray,
wavelength::Wavelength,
Box, Float, Vec, Vec3,
Box, Direction, Float, Position, Vec,
};

/// Bounding Volume Hierarchy Node.
Expand Down Expand Up @@ -187,26 +187,34 @@ impl<'scene> HitableTrait for BVHNode<'scene> {
#[must_use]
fn pdf_value(
&self,
origin: Vec3,
vector: Vec3,
origin: Position,
direction: Direction,
wavelength: Wavelength,
time: Float,
rng: &mut SmallRng,
) -> Float {
match (&*self.left, &*self.right) {
(_, Hitable::Empty(_)) => self.left.pdf_value(origin, vector, wavelength, time, rng),
(Hitable::Empty(_), _) => self.right.pdf_value(origin, vector, wavelength, time, rng),
(_, Hitable::Empty(_)) => self
.left
.pdf_value(origin, direction, wavelength, time, rng),
(Hitable::Empty(_), _) => self
.right
.pdf_value(origin, direction, wavelength, time, rng),
(_, _) => {
(self.left.pdf_value(origin, vector, wavelength, time, rng)
+ self.right.pdf_value(origin, vector, wavelength, time, rng))
(self
.left
.pdf_value(origin, direction, wavelength, time, rng)
+ self
.right
.pdf_value(origin, direction, wavelength, time, rng))
/ 2.0
}
}
}

/// Returns a random point on the surface of one of the children
#[must_use]
fn random(&self, origin: Vec3, rng: &mut SmallRng) -> Vec3 {
fn random(&self, origin: Position, rng: &mut SmallRng) -> Position {
match (&*self.left, &*self.right) {
(_, Hitable::Empty(_)) => self.left.random(origin, rng),
(Hitable::Empty(_), _) => self.right.random(origin, rng),
Expand Down
47 changes: 25 additions & 22 deletions clovers/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use crate::wavelength::random_wavelength;
use crate::{random::random_in_unit_disk, ray::Ray, Float, Vec3, PI};
use crate::{Direction, Position};
use nalgebra::Unit;
use rand::rngs::SmallRng;
use rand::Rng;

Expand All @@ -12,13 +14,13 @@ use rand::Rng;
/// The main [Camera] object used in the ray tracing.
pub struct Camera {
/// Coordinate of the lower left corner of the camera.
pub lower_left_corner: Vec3,
pub lower_left_corner: Position,
/// Defines the horizontal axis for the camera.
pub horizontal: Vec3,
/// Defines the vertical axis for the camera.
pub vertical: Vec3,
/// Defines the origin of the camera.
pub origin: Vec3,
pub origin: Position,
/// Defines the lens radius for the camera. TODO: understand and explain better
pub lens_radius: Float,
/// Defines the earliest starting time for the camera, used when generating [Rays](Ray).
Expand All @@ -27,21 +29,21 @@ pub struct Camera {
pub time_1: Float,
// TODO: clarify these odd one-letter variables
/// U
pub u: Vec3,
pub u: Direction,
/// V
pub v: Vec3,
pub v: Direction,
/// W
pub w: Vec3,
pub w: Direction,
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde-derive", derive(serde::Serialize, serde::Deserialize))]
/// Represents the fields that can be described in a Scene file. Some other fields the main Camera struct requires (such as `aspect_ratio`) are derived from other info (such as width, height)
pub struct CameraInit {
/// Describes where the camera is
pub look_from: Vec3,
pub look_from: Position,
/// Describes where the camera is looking at
pub look_at: Vec3,
pub look_at: Position,
/// Describes the subjective "up" direction for the camera to define the orientation
pub up: Vec3,
/// Describes the vertical field of view for the camera
Expand All @@ -57,8 +59,8 @@ impl Camera {
/// Creates a new [Camera] with the given parameters.
#[must_use]
pub fn new(
look_from: Vec3,
look_at: Vec3,
look_from: Position,
look_at: Position,
up: Vec3,
vertical_fov: Float,
aspect_ratio: Float,
Expand All @@ -71,18 +73,18 @@ impl Camera {
let theta: Float = vertical_fov * PI / 180.0;
let half_height: Float = (theta / 2.0).tan();
let half_width: Float = aspect_ratio * half_height;
let origin: Vec3 = look_from;
let w: Vec3 = (look_from - look_at).normalize();
let u: Vec3 = (up.cross(&w)).normalize();
let v: Vec3 = w.cross(&u);
let origin: Position = look_from;
let w: Direction = Unit::new_normalize(look_from - look_at);
let u: Direction = Unit::new_normalize(up.cross(&w));
let v: Direction = Unit::new_normalize(w.cross(&u));

// TODO: understand this defocus
let lower_left_corner: Vec3 = origin
- half_width * focus_distance * u
- half_height * focus_distance * v
- focus_distance * w;
let horizontal: Vec3 = 2.0 * half_width * focus_distance * u;
let vertical: Vec3 = 2.0 * half_height * focus_distance * v;
- half_width * focus_distance * *u
- half_height * focus_distance * *v
- focus_distance * *w;
let horizontal: Vec3 = 2.0 * half_width * focus_distance * *u;
let vertical: Vec3 = 2.0 * half_height * focus_distance * *v;

Camera {
lower_left_corner,
Expand All @@ -104,16 +106,17 @@ impl Camera {
pub fn get_ray(self, s: Float, t: Float, rng: &mut SmallRng) -> Ray {
// TODO: add a better defocus blur / depth of field implementation
let rd: Vec3 = self.lens_radius * random_in_unit_disk(rng);
let offset: Vec3 = self.u * rd.x + self.v * rd.y;
let offset: Vec3 = *self.u * rd.x + *self.v * rd.y;
// Randomized time used for motion blur
let time: Float = rng.gen_range(self.time_0..self.time_1);
// Random wavelength for spectral rendering
let wavelength = random_wavelength(rng);
let direction =
self.lower_left_corner + s * self.horizontal + t * self.vertical - self.origin - offset;
let direction = Unit::new_normalize(direction);
Ray {
origin: self.origin + offset,
direction: self.lower_left_corner + s * self.horizontal + t * self.vertical
- self.origin
- offset,
direction,
time,
wavelength,
}
Expand Down
5 changes: 4 additions & 1 deletion clovers/src/colorize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
wavelength::{wavelength_into_xyz, Wavelength},
Float, EPSILON_SHADOW_ACNE,
};
use nalgebra::Unit;
use palette::{
chromatic_adaptation::AdaptInto, convert::IntoColorUnclamped, white_point::E, Clamp, Xyz,
};
Expand Down Expand Up @@ -83,9 +84,11 @@ pub fn colorize(
hit_record.position,
));
let mixture_pdf = MixturePDF::new(light_ptr, scatter_record.pdf_ptr);
let direction = mixture_pdf.generate(rng);
let direction = Unit::new_normalize(direction);
let scatter_ray = Ray {
origin: hit_record.position,
direction: mixture_pdf.generate(rng),
direction,
time: ray.time,
wavelength: ray.wavelength,
};
Expand Down
22 changes: 11 additions & 11 deletions clovers/src/hitable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
objects::{Boxy, ConstantMedium, MovingSphere, Quad, RotateY, Sphere, Translate, Triangle},
ray::Ray,
wavelength::Wavelength,
Float, Vec3,
Direction, Float, Position,
};

use enum_dispatch::enum_dispatch;
Expand All @@ -26,9 +26,9 @@ pub struct HitRecord<'a> {
/// Distance from the ray origin to the hitpoint
pub distance: Float,
/// 3D coordinate of the hitpoint
pub position: Vec3,
pub position: Position,
/// Surface normal from the hitpoint
pub normal: Vec3,
pub normal: Direction,
/// U surface coordinate of the hitpoint
pub u: Float,
/// V surface coordinate of the hitpoint
Expand All @@ -41,7 +41,7 @@ pub struct HitRecord<'a> {

impl<'a> HitRecord<'a> {
/// Helper function for getting normals pointing at the correct direction. TODO: consider removal?
pub fn set_face_normal(&mut self, ray: &Ray, outward_normal: Vec3) {
pub fn set_face_normal(&mut self, ray: &Ray, outward_normal: Direction) {
self.front_face = ray.direction.dot(&outward_normal) < 0.0;
if self.front_face {
self.normal = outward_normal;
Expand Down Expand Up @@ -94,16 +94,16 @@ impl HitableTrait for Empty {

fn pdf_value(
&self,
_origin: Vec3,
_vector: Vec3,
_origin: Position,
_direction: Direction,
_wavelength: Wavelength,
_time: Float,
_rng: &mut SmallRng,
) -> Float {
0.0
}

fn random(&self, _origin: Vec3, _rng: &mut SmallRng) -> Vec3 {
fn random(&self, _origin: Position, _rng: &mut SmallRng) -> Position {
panic!("Hitable::Empty::random called!")
}
}
Expand All @@ -125,20 +125,20 @@ pub trait HitableTrait {
#[must_use]
fn pdf_value(
&self,
origin: Vec3,
vector: Vec3,
origin: Position,
direction: Direction,
wavelength: Wavelength,
time: Float,
rng: &mut SmallRng,
) -> Float;

#[must_use]
fn random(&self, origin: Vec3, rng: &mut SmallRng) -> Vec3;
fn random(&self, origin: Position, rng: &mut SmallRng) -> Position;
}

/// Returns a tuple of `(front_face, normal)`. Used in lieu of `set_face_normal` in the Ray Tracing for the Rest Of Your Life book.
#[must_use]
pub fn get_orientation(ray: &Ray, outward_normal: Vec3) -> (bool, Vec3) {
pub fn get_orientation(ray: &Ray, outward_normal: Direction) -> (bool, Direction) {
let front_face = ray.direction.dot(&outward_normal) < 0.0;
let normal = if front_face {
outward_normal
Expand Down
9 changes: 8 additions & 1 deletion clovers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ pub use alloc::boxed::Box;
pub use alloc::vec::Vec;

// Externals
use nalgebra::base::{Vector2, Vector3, Vector4};
use nalgebra::{
base::{Vector2, Vector3, Vector4},
Unit,
};

// Internals
pub mod aabb;
Expand Down Expand Up @@ -123,6 +126,10 @@ pub type Vec2 = Vector2<Float>;
pub type Vec3 = Vector3<Float>;
/// Internal type alias: a nalgebra [Vector4] which is a vector with four dimensions, containing four of our internal [Float] types
pub type Vec4 = Vector4<Float>;
/// Internal type alias: a nalgebra [Unit] of a [Vector3]
pub type Direction = Unit<Vec3>;
/// Internal type alias: a nalgebra [Vector3]
pub type Position = Vec3;
/// Internal const: epsilon used for avoiding "shadow acne". This is mostly used for the initial minimum distance for ray hits after reflecting or scattering from a surface.
pub const EPSILON_SHADOW_ACNE: Float = 0.001;
/// Internal const: epsilon used for having a finitely-sized thickness for the bounding box of an infinitely-thin rectangle. Shouldn't be too small.
Expand Down
20 changes: 11 additions & 9 deletions clovers/src/materials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

use alloc::string::String;
use core::fmt::Debug;
use nalgebra::Unit;

use crate::{hitable::HitRecord, pdf::PDF, ray::Ray, Float, Vec3};
use crate::{hitable::HitRecord, pdf::PDF, ray::Ray, Direction, Float, Position, Vec3};
pub mod cone_light;
pub mod dielectric;
pub mod diffuse_light;
Expand Down Expand Up @@ -79,7 +80,7 @@ pub trait MaterialTrait: Debug {
_hit_record: &HitRecord,
_u: Float,
_v: Float,
_position: Vec3,
_position: Position,
) -> Xyz<E> {
Xyz::new(0.0, 0.0, 0.0)
}
Expand Down Expand Up @@ -139,17 +140,18 @@ pub struct ScatterRecord<'ray> {
// TODO: are these up to date / correct?

#[must_use]
fn reflect(vector: Vec3, normal: Vec3) -> Vec3 {
vector - 2.0 * vector.dot(&normal) * normal
fn reflect(vector: Direction, normal: Direction) -> Direction {
let v: Vec3 = *vector - 2.0 * vector.dot(&normal) * *normal;
Unit::new_normalize(v)
}

#[must_use]
fn refract(uv: Vec3, normal: Vec3, refraction_ratio: Float) -> Vec3 {
let cos_theta: Float = -uv.dot(&normal);
fn refract(vector: Direction, normal: Direction, refraction_ratio: Float) -> Direction {
let cos_theta: Float = -vector.dot(&normal);
let cos_theta = cos_theta.min(1.0); // Clamp
let r_out_parallel: Vec3 = refraction_ratio * (uv + cos_theta * normal);
let r_out_perp: Vec3 = -(1.0 - r_out_parallel.norm_squared()).sqrt() * normal;
r_out_parallel + r_out_perp
let r_out_parallel: Vec3 = refraction_ratio * (*vector + cos_theta * *normal);
let r_out_perp: Vec3 = -(1.0 - r_out_parallel.norm_squared()).sqrt() * *normal;
Unit::new_normalize(r_out_parallel + r_out_perp)
}

#[must_use]
Expand Down
4 changes: 2 additions & 2 deletions clovers/src/materials/cone_light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
hitable::HitRecord,
ray::Ray,
textures::{SolidColor, Texture, TextureTrait},
Float, Vec3,
Float, Position,
};
use palette::{white_point::E, Xyz};
use rand::prelude::SmallRng;
Expand Down Expand Up @@ -59,7 +59,7 @@ impl MaterialTrait for ConeLight {
hit_record: &HitRecord,
u: Float,
v: Float,
position: Vec3,
position: Position,
) -> Xyz<E> {
// If we don't hit the front face, return black
if !hit_record.front_face {
Expand Down
Loading
Loading