refactor and many many more features
This commit is contained in:
parent
9a2d3405a1
commit
2083570909
68
Cargo.lock
generated
68
Cargo.lock
generated
|
@ -2,6 +2,74 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raytracer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
|
|
37
src/camera.rs
Normal file
37
src/camera.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use super::ray::Ray;
|
||||
use super::vec::{Point3, Vec3};
|
||||
|
||||
pub struct Camera {
|
||||
origin: Point3,
|
||||
lower_left_corner: Point3,
|
||||
horizontal: Vec3,
|
||||
vertical: Vec3,
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
pub fn new() -> Camera {
|
||||
const ASPECT_RATIO: f64 = 16.0 / 9.0;
|
||||
const VIEWPORT_HEIGHT: f64 = 2.0;
|
||||
const VIEWPORT_WIDTH: f64 = ASPECT_RATIO * VIEWPORT_HEIGHT;
|
||||
const FOCAL_LENGTH: f64 = 1.0;
|
||||
|
||||
let orig = Point3::new(0.0, 0.0, 0.0);
|
||||
let h = Vec3::new(VIEWPORT_WIDTH, 0.0, 0.0);
|
||||
let v = Vec3::new(0.0, VIEWPORT_HEIGHT, 0.0);
|
||||
let llc = orig - h / 2.0 - v / 2.0 - Vec3::new(0.0, 0.0, FOCAL_LENGTH);
|
||||
|
||||
Camera {
|
||||
origin: orig,
|
||||
horizontal: h,
|
||||
vertical: v,
|
||||
lower_left_corner: llc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
Ray::new(
|
||||
self.origin,
|
||||
self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin,
|
||||
)
|
||||
}
|
||||
}
|
44
src/display.rs
Normal file
44
src/display.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use core::fmt::Display;
|
||||
use core::fmt::Formatter;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DisplayInfo {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub aspect_ratio: f64,
|
||||
pub fps: u32,
|
||||
}
|
||||
impl Display for DisplayInfo {
|
||||
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DisplayInfo: {{ width: {}, height: {}, aspect_ratio: {}, fps: {} }}",
|
||||
self.width, self.height, self.aspect_ratio, self.fps
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_display_string(display_string: &str) -> Result<DisplayInfo, String> {
|
||||
let mut iter = display_string.split(&['x', '@']);
|
||||
let width = iter.next().ok_or("Display string must contain width")?;
|
||||
let height = iter.next().ok_or("Display string must contain height")?;
|
||||
let fps = iter.next().ok_or("Display string must contain fps")?;
|
||||
|
||||
let width = width
|
||||
.parse::<u32>()
|
||||
.map_err(|e| format!("Could not parse width: {}", e))?;
|
||||
let height = height
|
||||
.parse::<u32>()
|
||||
.map_err(|e| format!("Could not parse height: {}", e))?;
|
||||
let fps = fps
|
||||
.parse::<u32>()
|
||||
.map_err(|e| format!("Could not parse fps: {}", e))?;
|
||||
let dis_info = DisplayInfo {
|
||||
width,
|
||||
height,
|
||||
aspect_ratio: (width / height) as f64,
|
||||
fps,
|
||||
};
|
||||
|
||||
Ok(dis_info)
|
||||
}
|
43
src/hit.rs
Normal file
43
src/hit.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use crate::{
|
||||
ray::Ray,
|
||||
vec::{Point3, Vec3},
|
||||
};
|
||||
|
||||
pub struct HitRecord {
|
||||
pub p: Point3,
|
||||
pub normal: Vec3,
|
||||
pub t: f64,
|
||||
pub front_face: bool,
|
||||
}
|
||||
impl HitRecord {
|
||||
pub fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) -> () {
|
||||
self.front_face = r.direction().dot(outward_normal) < 0.0;
|
||||
self.normal = if self.front_face {
|
||||
outward_normal
|
||||
} else {
|
||||
(-1.0) * outward_normal
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Hit {
|
||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord>;
|
||||
}
|
||||
|
||||
pub type World = Vec<Box<dyn Hit>>;
|
||||
|
||||
impl Hit for World {
|
||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let mut tmp_rec = None;
|
||||
let mut closest_so_far = t_max;
|
||||
|
||||
for object in self {
|
||||
if let Some(rec) = object.hit(r, t_min, closest_so_far) {
|
||||
closest_so_far = rec.t;
|
||||
tmp_rec = Some(rec);
|
||||
}
|
||||
}
|
||||
|
||||
tmp_rec
|
||||
}
|
||||
}
|
121
src/main.rs
121
src/main.rs
|
@ -1,89 +1,78 @@
|
|||
use crate::{
|
||||
ray::Ray,
|
||||
utils::{Color3D, Header, Position3D, PpmFormat, Vec3},
|
||||
};
|
||||
pub mod camera;
|
||||
pub mod display;
|
||||
pub mod hit;
|
||||
pub mod ppm_format;
|
||||
mod ray;
|
||||
pub mod shapes;
|
||||
mod vec;
|
||||
|
||||
pub mod ray;
|
||||
pub mod utils;
|
||||
use std::io::{stderr, Write};
|
||||
|
||||
pub const WIDTH: u32 = 640;
|
||||
pub const HEIGHT: u32 = 480;
|
||||
use hit::Hit;
|
||||
use rand::Rng;
|
||||
use ray::Ray;
|
||||
use vec::{Color, Point3, Vec3};
|
||||
|
||||
pub const ASPECT_RATIO: f32 = WIDTH as f32 / HEIGHT as f32;
|
||||
use crate::{camera::Camera, hit::World, shapes::sphere::Sphere};
|
||||
|
||||
fn ray_color(r: &Ray, world: &World) -> Color {
|
||||
if let Some(rec) = world.hit(r, 0.0, f64::INFINITY) {
|
||||
0.5 * (rec.normal + Color::new(1.0, 1.0, 1.0))
|
||||
} else {
|
||||
let unit_direction = r.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
(1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let viewport_height = 2.0;
|
||||
let viewport_width = viewport_height * ASPECT_RATIO;
|
||||
let focal_length = 1.0;
|
||||
let xyz = "256x480@60";
|
||||
let display_info = display::parse_display_string(xyz).unwrap();
|
||||
|
||||
let origin = Position3D {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
const SAMPLES_PER_PIXEL: u64 = 100;
|
||||
|
||||
let horizontal = Position3D {
|
||||
x: viewport_width,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
// World
|
||||
let mut world = World::new();
|
||||
world.push(Box::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));
|
||||
world.push(Box::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
|
||||
|
||||
let vertical = Position3D {
|
||||
x: 0.0,
|
||||
y: viewport_height,
|
||||
z: 0.0,
|
||||
};
|
||||
// Camera
|
||||
let cam = Camera::new();
|
||||
|
||||
let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - focal_length;
|
||||
println!("P3");
|
||||
println!("{} {}", display_info.width, display_info.height);
|
||||
println!("255");
|
||||
|
||||
let header = Header {
|
||||
format: PpmFormat::P3,
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
max_color: 255,
|
||||
};
|
||||
println!("# {}", ASPECT_RATIO);
|
||||
println!("{}", header);
|
||||
use std::time::Instant;
|
||||
let now = Instant::now();
|
||||
|
||||
// Code block to measure.
|
||||
let mut rng = rand::thread_rng();
|
||||
{
|
||||
for y in 0..HEIGHT {
|
||||
for x in 0..WIDTH {
|
||||
let u = (x / WIDTH) as f32 - 1.0;
|
||||
let v = (y / HEIGHT) as f32 - 1.0;
|
||||
for j in (0..display_info.height).rev() {
|
||||
eprint!("\rScanlines remaining: {:3}", display_info.height - j - 1);
|
||||
stderr().flush().unwrap();
|
||||
|
||||
let bcr = lower_left_corner + u * horizontal + v * vertical - origin;
|
||||
for i in 0..display_info.width {
|
||||
let mut pixel_color = Color::new(0.0, 0.0, 0.0);
|
||||
for _ in 0..SAMPLES_PER_PIXEL {
|
||||
let random_u: f64 = rng.gen();
|
||||
let random_v: f64 = rng.gen();
|
||||
|
||||
let ray = Ray {
|
||||
origin,
|
||||
direction: bcr,
|
||||
};
|
||||
let u = ((i as f64) + random_u) / ((display_info.width - 1) as f64);
|
||||
let v = ((j as f64) + random_v) / ((display_info.height - 1) as f64);
|
||||
|
||||
let rgb_color = ray_color(&ray);
|
||||
println!("{}", rgb_color);
|
||||
}
|
||||
let r = cam.get_ray(u, v);
|
||||
pixel_color += ray_color(&r, &world);
|
||||
}
|
||||
|
||||
println!("{}", pixel_color.format_color(SAMPLES_PER_PIXEL));
|
||||
}
|
||||
}
|
||||
|
||||
fn unit_vector(v: &Vec3) -> Vec3 {
|
||||
*v / v.length()
|
||||
let elapsed = now.elapsed();
|
||||
eprintln!("\nElapsed: {:.2?}", elapsed);
|
||||
}
|
||||
|
||||
fn ray_color(ray: &ray::Ray) -> Color3D {
|
||||
let unit_dir = unit_vector(&ray.direction);
|
||||
let t = 0.5 * (unit_dir.y + 1.0);
|
||||
|
||||
let color1 = Color3D {
|
||||
x: 1.0,
|
||||
y: 1.0,
|
||||
z: 1.0,
|
||||
};
|
||||
let color2 = Color3D {
|
||||
x: 0.5,
|
||||
y: 0.7,
|
||||
z: 1.0,
|
||||
};
|
||||
|
||||
return (1.0 - t) * color1 + t * color2;
|
||||
eprintln!("\nDone.");
|
||||
}
|
||||
|
|
11
src/ppm_format.rs
Normal file
11
src/ppm_format.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// What does this do?
|
||||
pub enum PpmFormat {
|
||||
P3,
|
||||
}
|
||||
|
||||
pub struct Header {
|
||||
ppm_format: PpmFormat,
|
||||
width: usize,
|
||||
height: usize,
|
||||
max_color_value: usize,
|
||||
}
|
24
src/ray.rs
24
src/ray.rs
|
@ -1,6 +1,24 @@
|
|||
use crate::utils::Position3D;
|
||||
use super::vec::{Point3, Vec3};
|
||||
|
||||
pub struct Ray {
|
||||
pub origin: Position3D,
|
||||
pub direction: Position3D,
|
||||
pub origin: Point3,
|
||||
pub direction: Vec3,
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(origin: Point3, direction: Vec3) -> Ray {
|
||||
Ray { origin, direction }
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> Point3 {
|
||||
self.origin
|
||||
}
|
||||
|
||||
pub fn direction(&self) -> Vec3 {
|
||||
self.direction
|
||||
}
|
||||
|
||||
pub fn at(&self, t: f64) -> Point3 {
|
||||
self.origin + t * self.direction
|
||||
}
|
||||
}
|
||||
|
|
1
src/shapes/mod.rs
Normal file
1
src/shapes/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod sphere;
|
56
src/shapes/sphere.rs
Normal file
56
src/shapes/sphere.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use crate::{
|
||||
hit::{Hit, HitRecord},
|
||||
ray::Ray,
|
||||
vec::{Point3, Vec3},
|
||||
};
|
||||
|
||||
pub struct Sphere {
|
||||
center: Point3,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(cen: Point3, r: f64) -> Sphere {
|
||||
Sphere {
|
||||
center: cen,
|
||||
radius: r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hit for Sphere {
|
||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let oc = r.origin() - self.center;
|
||||
let a = r.direction().length().powi(2);
|
||||
let half_b = oc.dot(r.direction());
|
||||
let c = oc.length().powi(2) - self.radius.powi(2);
|
||||
|
||||
let discriminant = half_b.powi(2) - a * c;
|
||||
if discriminant < 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Find the nearest root that lies in the acceptable range
|
||||
let sqrtd = discriminant.sqrt();
|
||||
let mut root = (-half_b - sqrtd) / a;
|
||||
if root < t_min || t_max < root {
|
||||
root = (-half_b + sqrtd) / a;
|
||||
if root < t_min || t_max < root {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let p = r.at(root);
|
||||
let mut rec = HitRecord {
|
||||
t: root,
|
||||
p,
|
||||
|
||||
normal: Vec3::new(0.0, 0.0, 0.0),
|
||||
front_face: false,
|
||||
};
|
||||
let outward_normal = (rec.p - self.center) / self.radius;
|
||||
rec.set_face_normal(r, outward_normal);
|
||||
|
||||
Some(rec)
|
||||
}
|
||||
}
|
133
src/utils.rs
133
src/utils.rs
|
@ -1,133 +0,0 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
};
|
||||
|
||||
pub type Position3D = Vec3;
|
||||
pub type Color3D = Vec3;
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Vec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
impl Vec3 {
|
||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
pub fn zero() -> Self {
|
||||
Self::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
pub fn length(&self) -> f32 {
|
||||
self.length_squared().sqrt()
|
||||
}
|
||||
pub fn length_squared(&self) -> f32 {
|
||||
self.x * self.x + self.y * self.y + self.z * self.z
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x * rhs,
|
||||
y: self.y * rhs,
|
||||
z: self.z * rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn add(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
z: self.z + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn add(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn sub(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x - rhs,
|
||||
y: self.y - rhs,
|
||||
z: self.z - rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn sub(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn div(self, rhs: f32) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self.x / rhs,
|
||||
y: self.y / rhs,
|
||||
z: self.z / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for f32 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, rhs: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
x: self * rhs.x,
|
||||
y: self * rhs.y,
|
||||
z: self * rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{} {} {}", self.x as u8, self.y as u8, self.z as u8)
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum PpmFormat {
|
||||
P3,
|
||||
}
|
||||
|
||||
pub struct Header {
|
||||
pub format: PpmFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub max_color: u8,
|
||||
}
|
||||
|
||||
impl Display for Header {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"# HEADER BEGIN
|
||||
{:?}\n{} {}\n{}
|
||||
# HEADER END",
|
||||
self.format, self.width, self.height, self.max_color
|
||||
)
|
||||
}
|
||||
}
|
171
src/vec.rs
Normal file
171
src/vec.rs
Normal file
|
@ -0,0 +1,171 @@
|
|||
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign};
|
||||
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Vec3 {
|
||||
e: [f64; 3],
|
||||
}
|
||||
|
||||
pub type Point3 = Vec3;
|
||||
pub type Color = Vec3;
|
||||
|
||||
impl Vec3 {
|
||||
pub fn new(e0: f64, e1: f64, e2: f64) -> Vec3 {
|
||||
Vec3 { e: [e0, e1, e2] }
|
||||
}
|
||||
|
||||
pub fn x(self) -> f64 {
|
||||
self[0]
|
||||
}
|
||||
|
||||
pub fn y(self) -> f64 {
|
||||
self[1]
|
||||
}
|
||||
|
||||
pub fn z(self) -> f64 {
|
||||
self[2]
|
||||
}
|
||||
|
||||
pub fn dot(self, other: Vec3) -> f64 {
|
||||
self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
|
||||
}
|
||||
|
||||
pub fn length(self) -> f64 {
|
||||
self.dot(self).sqrt()
|
||||
}
|
||||
pub fn length_squared(self) -> f64 {
|
||||
self.dot(self)
|
||||
}
|
||||
|
||||
pub fn cross(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [
|
||||
self[1] * other[2] - self[2] * other[1],
|
||||
self[2] * other[0] - self[0] * other[2],
|
||||
self[0] * other[1] - self[1] * other[0],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalized(self) -> Vec3 {
|
||||
self / self.length()
|
||||
}
|
||||
|
||||
/*pub fn format_color(self) -> String {
|
||||
format!(
|
||||
"{} {} {}",
|
||||
(255.999 * self[0]) as u64,
|
||||
(255.999 * self[1]) as u64,
|
||||
(255.999 * self[2]) as u64
|
||||
)
|
||||
}*/
|
||||
pub fn format_color(self, samples_per_pixel: u64) -> String {
|
||||
let ir = (256.0 * (self[0] / (samples_per_pixel as f64)).clamp(0.0, 0.999)) as u64;
|
||||
let ig = (256.0 * (self[1] / (samples_per_pixel as f64)).clamp(0.0, 0.999)) as u64;
|
||||
let ib = (256.0 * (self[2] / (samples_per_pixel as f64)).clamp(0.0, 0.999)) as u64;
|
||||
|
||||
format!("{} {} {}", ir, ig, ib)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Vec3 {
|
||||
type Output = f64;
|
||||
|
||||
fn index(&self, index: usize) -> &f64 {
|
||||
&self.e[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec3 {
|
||||
fn index_mut(&mut self, index: usize) -> &mut f64 {
|
||||
&mut self.e[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn add(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [self[0] + other[0], self[1] + other[1], self[2] + other[2]],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Vec3 {
|
||||
fn add_assign(&mut self, other: Vec3) -> () {
|
||||
*self = Vec3 {
|
||||
e: [self[0] + other[0], self[1] + other[1], self[2] + other[2]],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn sub(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [self[0] - other[0], self[1] - other[1], self[2] - other[2]],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Vec3 {
|
||||
fn sub_assign(&mut self, other: Vec3) -> () {
|
||||
*self = Vec3 {
|
||||
e: [self[0] - other[0], self[1] - other[1], self[2] - other[2]],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn mul(self, other: f64) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [self[0] * other, self[1] * other, self[2] * other],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, other: f64) -> () {
|
||||
*self = Vec3 {
|
||||
e: [self[0] * other, self[1] * other, self[2] * other],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for f64 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn mul(self, other: Vec3) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [self * other[0], self * other[1], self * other[2]],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, other: f64) -> Vec3 {
|
||||
Vec3 {
|
||||
e: [self[0] / other, self[1] / other, self[2] / other],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f64> for Vec3 {
|
||||
fn div_assign(&mut self, other: f64) -> () {
|
||||
*self = Vec3 {
|
||||
e: [self[0] / other, self[1] / other, self[2] / other],
|
||||
};
|
||||
}
|
||||
}
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({}, {}, {})", self[0], self[1], self[2])
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue