430 lines
8.3 KiB
Rust
430 lines
8.3 KiB
Rust
use core::f32::math::sqrt;
|
|
use is_close::default;
|
|
use rand::RngExt;
|
|
use serde::Deserialize;
|
|
use std::{
|
|
fmt::Display,
|
|
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
|
};
|
|
|
|
#[derive(Copy, Clone, Debug, Deserialize)]
|
|
pub struct Vec3 {
|
|
x: f32,
|
|
y: f32,
|
|
z: f32,
|
|
}
|
|
|
|
pub type Colour = Vec3;
|
|
|
|
impl Vec3 {
|
|
pub fn new(r: f32, g: f32, b: f32) -> Self {
|
|
Self { x: r, y: g, z: b }
|
|
}
|
|
|
|
pub fn nil() -> Self {
|
|
Self {
|
|
x: 0.,
|
|
y: 0.,
|
|
z: 0.,
|
|
}
|
|
}
|
|
|
|
pub fn random() -> Self {
|
|
let mut rng = rand::rng();
|
|
Self {
|
|
x: rng.random_range(-1.0..1.),
|
|
y: rng.random_range(-1.0..1.),
|
|
z: rng.random_range(-1.0..1.),
|
|
}
|
|
}
|
|
|
|
pub fn random_unit() -> Self {
|
|
loop {
|
|
let v = Self::random();
|
|
if v.length_squared() <= 1. {
|
|
return v / v.length();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn random_unit_hemisphere(n: &Self) -> Self {
|
|
let v = Self::random_unit();
|
|
if n.dot(&v) > 0.0 {
|
|
v
|
|
} else {
|
|
-v
|
|
}
|
|
}
|
|
|
|
pub fn x(&self) -> &f32 {
|
|
&self.x
|
|
}
|
|
|
|
pub fn y(&self) -> &f32 {
|
|
&self.y
|
|
}
|
|
|
|
pub fn z(&self) -> &f32 {
|
|
&self.z
|
|
}
|
|
|
|
pub fn length(&self) -> f32 {
|
|
sqrt(self.length_squared())
|
|
}
|
|
|
|
pub fn length_squared(&self) -> f32 {
|
|
(self.x * self.x + self.y * self.y + self.z * self.z) as f32
|
|
}
|
|
|
|
pub fn dot(&self, other: &Self) -> f32 {
|
|
self.x * other.x + self.y * other.y + self.z * other.z
|
|
}
|
|
|
|
pub fn cross(&self, other: &Self) -> Self {
|
|
Self {
|
|
x: self.y * other.z - self.z * other.y,
|
|
y: self.z * other.x - self.x * other.z,
|
|
z: self.x * other.y - self.y * other.x,
|
|
}
|
|
}
|
|
|
|
pub fn make_unit(mut self) {
|
|
self /= self.length();
|
|
}
|
|
|
|
pub fn get_unit(self) -> Self {
|
|
self / self.length()
|
|
}
|
|
|
|
pub fn near_zero(&self) -> bool {
|
|
default().is_close(self.x, 0.)
|
|
&& default().is_close(self.y, 0.)
|
|
&& default().is_close(self.z, 0.)
|
|
}
|
|
|
|
pub fn reflect(&self, n: &Self) -> Self {
|
|
*self - 2. * (self.dot(n) * n)
|
|
}
|
|
|
|
pub fn refract(&self, n: &Self, etai_over_etat: f32) -> Self {
|
|
let mut cos_theta = -self.dot(n);
|
|
cos_theta = if cos_theta > 1.0 { 1.0 } else { cos_theta };
|
|
|
|
let r_out_perp = etai_over_etat * (*self + cos_theta * n);
|
|
let r_out_parr = -sqrt((1. - r_out_perp.length_squared()).abs()) * n;
|
|
|
|
return r_out_perp + r_out_parr;
|
|
}
|
|
|
|
pub fn output(self) -> image::Rgb<u8> {
|
|
// gamma correction
|
|
let r = if self.x > 0. {
|
|
sqrt(self.x).clamp(0., 1.)
|
|
} else {
|
|
0.
|
|
};
|
|
let g = if self.y > 0. {
|
|
sqrt(self.y).clamp(0., 1.)
|
|
} else {
|
|
0.
|
|
};
|
|
let b = if self.z > 0. {
|
|
sqrt(self.z).clamp(0.1, 1.)
|
|
} else {
|
|
0.
|
|
};
|
|
|
|
let ir = (255.599 * r) as u8;
|
|
let ig = (255.599 * g) as u8;
|
|
let ib = (255.599 * b) as u8;
|
|
|
|
image::Rgb([ir, ig, ib])
|
|
}
|
|
|
|
pub fn clone(&self) -> Self {
|
|
Self {
|
|
x: self.x,
|
|
y: self.y,
|
|
z: self.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Vec3 {
|
|
fn default() -> Self {
|
|
Self {
|
|
x: 0.,
|
|
y: 0.,
|
|
z: 0.,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Neg for &Vec3 {
|
|
type Output = Vec3;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
-*self
|
|
}
|
|
}
|
|
|
|
impl Neg for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
Self {
|
|
x: -self.x,
|
|
y: -self.y,
|
|
z: -self.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Add<Vec3> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn add(self, _rhs: Self) -> Self {
|
|
Self {
|
|
x: self.x + _rhs.x,
|
|
y: self.y + _rhs.y,
|
|
z: self.z + _rhs.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Add<f32> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn add(self, f: f32) -> Self {
|
|
Self {
|
|
x: self.x + f,
|
|
y: self.y + f,
|
|
z: self.z + f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AddAssign<Vec3> for Vec3 {
|
|
fn add_assign(&mut self, other: Self) {
|
|
*self = Self {
|
|
x: self.x + other.x,
|
|
y: self.y + other.y,
|
|
z: self.z + other.z,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl AddAssign<f32> for Vec3 {
|
|
fn add_assign(&mut self, f: f32) {
|
|
*self = Self {
|
|
x: self.x + f,
|
|
y: self.y + f,
|
|
z: self.z + f,
|
|
};
|
|
}
|
|
}
|
|
impl Sub<&Vec3> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn sub(self, rhs: &Self) -> Self {
|
|
Self {
|
|
x: self.x - rhs.x,
|
|
y: self.y - rhs.y,
|
|
z: self.z - rhs.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Sub<Vec3> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn sub(self, rhs: Self) -> Self {
|
|
Self {
|
|
x: self.x - rhs.x,
|
|
y: self.y - rhs.y,
|
|
z: self.z - rhs.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Sub<f32> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn sub(self, f: f32) -> Self {
|
|
Self {
|
|
x: self.x - f,
|
|
y: self.y - f,
|
|
z: self.z - f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SubAssign<Vec3> for Vec3 {
|
|
fn sub_assign(&mut self, rhs: Self) {
|
|
*self = Self {
|
|
x: self.x - rhs.x,
|
|
y: self.y - rhs.y,
|
|
z: self.z - rhs.z,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl SubAssign<f32> for Vec3 {
|
|
fn sub_assign(&mut self, f: f32) {
|
|
*self = Self {
|
|
x: self.x - f,
|
|
y: self.y - f,
|
|
z: self.z - f,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl Mul<Vec3> for Vec3 {
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: Self) -> Self::Output {
|
|
Self {
|
|
x: self.x * rhs.x,
|
|
y: self.y * rhs.y,
|
|
z: self.z * rhs.z,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Mul<Vec3> for u32 {
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: Vec3) -> Self::Output {
|
|
let f = self as f32;
|
|
Vec3 {
|
|
x: rhs.x * f,
|
|
y: rhs.y * f,
|
|
z: rhs.z * f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Mul<f32> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn mul(self, f: f32) -> Self::Output {
|
|
Self {
|
|
x: self.x * f,
|
|
y: self.y * f,
|
|
z: self.z * f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Mul<Vec3> for f32 {
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: Vec3) -> Self::Output {
|
|
Vec3 {
|
|
x: rhs.x * self,
|
|
y: rhs.y * self,
|
|
z: rhs.z * self,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Mul<&Vec3> for f32 {
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: &Vec3) -> Self::Output {
|
|
Vec3 {
|
|
x: rhs.x * self,
|
|
y: rhs.y * self,
|
|
z: rhs.z * self,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MulAssign<Vec3> for Vec3 {
|
|
fn mul_assign(&mut self, rhs: Self) {
|
|
*self = Self {
|
|
x: self.x * rhs.x,
|
|
y: self.y * rhs.y,
|
|
z: self.z * rhs.z,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl MulAssign<f32> for Vec3 {
|
|
fn mul_assign(&mut self, f: f32) {
|
|
*self = Self {
|
|
x: self.x * f,
|
|
y: self.y * f,
|
|
z: self.z * f,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl Div<Vec3> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn div(self, rhs: Self) -> Self::Output {
|
|
Self {
|
|
x: self.x / rhs.x,
|
|
y: self.y / rhs.y,
|
|
z: self.z / rhs.z,
|
|
}
|
|
}
|
|
}
|
|
impl Div<i32> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn div(self, i: i32) -> Self::Output {
|
|
let f: f32 = i as f32;
|
|
Self {
|
|
x: self.x / f,
|
|
y: self.y / f,
|
|
z: self.z / f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Div<f32> for Vec3 {
|
|
type Output = Self;
|
|
|
|
fn div(self, f: f32) -> Self::Output {
|
|
Self {
|
|
x: self.x / f,
|
|
y: self.y / f,
|
|
z: self.z / f,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DivAssign<Vec3> for Vec3 {
|
|
fn div_assign(&mut self, rhs: Self) {
|
|
*self = Self {
|
|
x: self.x / rhs.x,
|
|
y: self.y / rhs.y,
|
|
z: self.z / rhs.z,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl DivAssign<f32> for Vec3 {
|
|
fn div_assign(&mut self, f: f32) {
|
|
*self = Self {
|
|
x: self.x / f,
|
|
y: self.y / f,
|
|
z: self.z / f,
|
|
};
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Vec3 {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.x == other.x && self.y == other.y && self.z == other.z
|
|
}
|
|
}
|
|
|
|
impl Display for Vec3 {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "({}, {}, {})", self.x, self.y, self.z)
|
|
}
|
|
}
|