Compare commits
6 Commits
6bf65eb60c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 076bcc7155 | |||
| 430bdf63bc | |||
| ef8da70436 | |||
| 5f2c419af5 | |||
| ffad2f12e4 | |||
| 79e6d04e50 |
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -1240,6 +1240,8 @@ dependencies = [
|
|||||||
"ops",
|
"ops",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rand 0.10.1",
|
"rand 0.10.1",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1311,6 +1313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ log = "0.4.29"
|
|||||||
ops = "0.6.0"
|
ops = "0.6.0"
|
||||||
pretty_env_logger = "0.5.0"
|
pretty_env_logger = "0.5.0"
|
||||||
rand = "0.10.1"
|
rand = "0.10.1"
|
||||||
|
serde = {version = "1.0.228", features = ["derive"]}
|
||||||
|
serde_json = "1.0.149"
|
||||||
|
|||||||
22
scenes/failsMatBounds.json
Normal file
22
scenes/failsMatBounds.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"camera": {
|
||||||
|
"image_width": 1920,
|
||||||
|
"image_height": 1080,
|
||||||
|
"anti_alias_rate": 1,
|
||||||
|
"max_depth": 10,
|
||||||
|
"fov": 90.0,
|
||||||
|
"look_from": { "x": -10, "y": 5, "z": 10 },
|
||||||
|
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
|
||||||
|
"vup": { "x": 0.0, "y": 1.0, "z": 0.0 }
|
||||||
|
},
|
||||||
|
"materials": [
|
||||||
|
{ "type": "metal", "albedo": { "x": 0.2, "y": 0.4, "z": 0.8 }, "prob": 1.0, "fuzz": 0.1 }
|
||||||
|
|
||||||
|
],
|
||||||
|
"objects": [
|
||||||
|
{ "type": "sphere", "center": { "x": 0, "y": 0.7, "z": -0.4 }, "radius": 0.2, "material": 1}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
34
scenes/scene.json
Normal file
34
scenes/scene.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"camera": {
|
||||||
|
"image_width": 1920,
|
||||||
|
"image_height": 1080,
|
||||||
|
"anti_alias_rate": 23,
|
||||||
|
"max_depth": 100,
|
||||||
|
"fov": 40.0,
|
||||||
|
"look_from": { "x": -10, "y": 5, "z": 10 },
|
||||||
|
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
|
||||||
|
"vup": { "x": 0.0, "y": 1.0, "z": 0.0 }
|
||||||
|
},
|
||||||
|
"materials": [
|
||||||
|
{ "type": "metal", "albedo": { "x": 0.2, "y": 0.4, "z": 0.8 }, "prob": 1.0, "fuzz": 0.1 },
|
||||||
|
{ "type": "metal", "albedo": { "x": 0.7, "y": 0.4, "z": 0.2 }, "prob": 1.0, "fuzz": 0.1 },
|
||||||
|
{ "type": "lambertian", "albedo": { "x": 0.8, "y": 0.8, "z": 0.0 }, "prob": 1.0 },
|
||||||
|
{ "type": "lambertian", "albedo": { "x": 0.1, "y": 0.2, "z": 0.5 }, "prob": 1.0 },
|
||||||
|
{ "type": "dielectric", "refraction_index": 1.5},
|
||||||
|
{ "type": "dielectric", "refraction_index": 0.67},
|
||||||
|
{ "type": "metal", "albedo": { "x": 0.8, "y": 0.6, "z": 0.2 }, "prob": 1.0, "fuzz": 1.0 }
|
||||||
|
|
||||||
|
],
|
||||||
|
"objects": [
|
||||||
|
{ "type": "sphere", "center": { "x": 0, "y": 0.7, "z": -0.4 }, "radius": 0.2, "material": 0},
|
||||||
|
{ "type": "sphere", "center": { "x": 0.0, "y": 0.5, "z": -0.8 }, "radius": 0.1, "material": 1},
|
||||||
|
{ "type": "sphere", "center": { "x": 0.0, "y": -100.5, "z": -1.0 }, "radius": 100.0, "material": 2},
|
||||||
|
{ "type": "sphere", "center": { "x": 0.0, "y": 0.0, "z": -1.2 }, "radius": 0.5, "material": 3},
|
||||||
|
{ "type": "sphere", "center": { "x": -1, "y": 0, "z": -1 }, "radius": 0.4, "material": 5},
|
||||||
|
{ "type": "sphere", "center": { "x": 1, "y": 0, "z": -1 }, "radius": 0.5, "material": 6},
|
||||||
|
{ "type": "sphere", "center": { "x": 20, "y": 7, "z": -15 }, "radius": 10.5, "material": 0}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
180
src/camera.rs
180
src/camera.rs
@@ -1,6 +1,7 @@
|
|||||||
use std::cmp::max;
|
use std::{f32::consts::PI, sync::Arc};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{hit::Hit, traits::Hittable},
|
objects::{hit::Hit, traits::Hittable},
|
||||||
@@ -8,50 +9,157 @@ use crate::{
|
|||||||
vec3::{Colour, Vec3},
|
vec3::{Colour, Vec3},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
|
// output
|
||||||
image_width: u32,
|
image_width: u32,
|
||||||
image_height: u32,
|
image_height: u32,
|
||||||
|
|
||||||
|
// raytracing
|
||||||
anti_alias_rate: u32,
|
anti_alias_rate: u32,
|
||||||
max_depth: u32,
|
max_depth: u32,
|
||||||
center: Vec3,
|
|
||||||
pixel00_loc: Vec3,
|
pixel00_loc: Vec3,
|
||||||
pixel_delta_u: Vec3,
|
pixel_delta_u: Vec3,
|
||||||
pixel_delta_v: Vec3,
|
pixel_delta_v: Vec3,
|
||||||
|
|
||||||
|
// camera
|
||||||
|
dirty: bool,
|
||||||
|
fov: f32,
|
||||||
|
look_from: Vec3,
|
||||||
|
look_at: Vec3,
|
||||||
|
vup: Vec3,
|
||||||
|
|
||||||
|
// camera helpers
|
||||||
|
u: Vec3,
|
||||||
|
v: Vec3,
|
||||||
|
w: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: kinda out of place in this file.
|
||||||
|
fn deg_to_rad(deg: f32) -> f32 {
|
||||||
|
deg * PI / 180.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera {
|
impl Camera {
|
||||||
pub fn new(aspect_ratio: f32, image_width: u32, anti_alias_rate: u32, max_depth: u32) -> Self {
|
pub fn new(image_width: u32, image_height: u32) -> Self {
|
||||||
let image_height = max(1, (image_width as f32 / aspect_ratio) as u32);
|
|
||||||
|
|
||||||
//camera
|
|
||||||
let focal_length = 1.;
|
|
||||||
let viewport_height = 2.;
|
|
||||||
let viewport_width = viewport_height * (image_width as f32 / image_height as f32);
|
|
||||||
let camera_center = Vec3::nil();
|
|
||||||
|
|
||||||
//viewport
|
|
||||||
let viewport_u = Vec3::new(viewport_width as f32, 0., 0.);
|
|
||||||
let viewport_v = Vec3::new(0., -viewport_height as f32, 0.);
|
|
||||||
|
|
||||||
let pixel_delta_u = viewport_u / image_width as f32;
|
|
||||||
let pixel_delta_v = viewport_v / image_height as f32;
|
|
||||||
|
|
||||||
let pixel00_loc =
|
|
||||||
camera_center - Vec3::new(0., 0., focal_length) - viewport_u / 2 - viewport_v / 2;
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
image_width: image_width,
|
image_width,
|
||||||
image_height: image_height,
|
image_height,
|
||||||
anti_alias_rate: anti_alias_rate,
|
anti_alias_rate: 1,
|
||||||
max_depth: max_depth,
|
max_depth: 10,
|
||||||
center: camera_center,
|
dirty: true,
|
||||||
pixel00_loc: pixel00_loc,
|
fov: 60.,
|
||||||
pixel_delta_u: pixel_delta_u,
|
pixel00_loc: Vec3::default(),
|
||||||
pixel_delta_v: pixel_delta_v,
|
pixel_delta_u: Vec3::default(),
|
||||||
|
pixel_delta_v: Vec3::default(),
|
||||||
|
look_from: Vec3::nil(),
|
||||||
|
look_at: Vec3::new(0., 0., -1.),
|
||||||
|
vup: Vec3::new(0., 1., 0.),
|
||||||
|
u: Vec3::default(),
|
||||||
|
v: Vec3::default(),
|
||||||
|
w: Vec3::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render<T: Hittable>(&self, hittables: &Vec<T>) {
|
pub fn new_full(
|
||||||
|
image_width: u32,
|
||||||
|
image_height: u32,
|
||||||
|
anti_alias_rate: u32,
|
||||||
|
max_depth: u32,
|
||||||
|
fov: f32,
|
||||||
|
look_from: Vec3,
|
||||||
|
look_at: Vec3,
|
||||||
|
vup: Vec3,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
image_width,
|
||||||
|
image_height,
|
||||||
|
anti_alias_rate,
|
||||||
|
max_depth,
|
||||||
|
pixel00_loc: Vec3::default(),
|
||||||
|
pixel_delta_u: Vec3::default(),
|
||||||
|
pixel_delta_v: Vec3::default(),
|
||||||
|
dirty: true,
|
||||||
|
fov,
|
||||||
|
look_from,
|
||||||
|
look_at,
|
||||||
|
vup,
|
||||||
|
u: Vec3::default(),
|
||||||
|
v: Vec3::default(),
|
||||||
|
w: Vec3::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
// camera
|
||||||
|
let focal_length = (self.look_from - self.look_at).length();
|
||||||
|
let theta = deg_to_rad(self.fov);
|
||||||
|
let h = (theta / 2.).tan();
|
||||||
|
self.w = (self.look_from - self.look_at).get_unit();
|
||||||
|
self.u = self.vup.cross(&self.w).get_unit();
|
||||||
|
self.v = self.w.cross(&self.u);
|
||||||
|
|
||||||
|
// viewport
|
||||||
|
let viewport_height = 2. * h * focal_length;
|
||||||
|
let viewport_width = viewport_height * (self.image_width as f32 / self.image_height as f32);
|
||||||
|
let viewport_u = viewport_width * self.u;
|
||||||
|
let viewport_v = viewport_height * -self.v;
|
||||||
|
|
||||||
|
// variables
|
||||||
|
self.pixel_delta_u = viewport_u / self.image_width as f32;
|
||||||
|
self.pixel_delta_v = viewport_v / self.image_height as f32;
|
||||||
|
self.pixel00_loc =
|
||||||
|
self.look_from - (focal_length * self.w) - viewport_u / 2. - viewport_v / 2.;
|
||||||
|
self.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_fov(&mut self, fov: f32) {
|
||||||
|
if self.fov != fov {
|
||||||
|
self.fov = fov;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_max_depth(&mut self, depth: u32) {
|
||||||
|
if self.max_depth != depth {
|
||||||
|
self.max_depth = depth;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_anti_alias_rate(&mut self, rate: u32) {
|
||||||
|
if self.anti_alias_rate != rate {
|
||||||
|
self.anti_alias_rate = rate;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_look_from(&mut self, look_from: Vec3) {
|
||||||
|
if self.look_from != look_from {
|
||||||
|
self.look_from = look_from;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_look_at(&mut self, look_at: Vec3) {
|
||||||
|
if self.look_at != look_at {
|
||||||
|
self.look_at = look_at;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_vup(&mut self, vup: Vec3) {
|
||||||
|
if self.vup != vup {
|
||||||
|
self.vup = vup;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, hittables: &Vec<Arc<dyn Hittable>>) {
|
||||||
|
if self.dirty {
|
||||||
|
self.init()
|
||||||
|
}
|
||||||
|
|
||||||
let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height);
|
let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height);
|
||||||
|
|
||||||
// render
|
// render
|
||||||
@@ -61,14 +169,14 @@ impl Camera {
|
|||||||
let pixel_tl =
|
let pixel_tl =
|
||||||
self.pixel00_loc + (i * self.pixel_delta_u) + (j * self.pixel_delta_v);
|
self.pixel00_loc + (i * self.pixel_delta_u) + (j * self.pixel_delta_v);
|
||||||
|
|
||||||
let mut pixel_colour = Colour::nil();
|
let mut pixel_colour = Colour::default();
|
||||||
for y in 1..(self.anti_alias_rate + 1) {
|
for y in 1..(self.anti_alias_rate + 1) {
|
||||||
for x in 1..(self.anti_alias_rate + 1) {
|
for x in 1..(self.anti_alias_rate + 1) {
|
||||||
let pixel_loc = pixel_tl
|
let pixel_loc = pixel_tl
|
||||||
+ (x * self.pixel_delta_u / (self.anti_alias_rate + 1) as f32)
|
+ (x * self.pixel_delta_u / (self.anti_alias_rate + 1) as f32)
|
||||||
+ (y * self.pixel_delta_v / (self.anti_alias_rate + 1) as f32);
|
+ (y * self.pixel_delta_v / (self.anti_alias_rate + 1) as f32);
|
||||||
let ray_dir = pixel_loc - self.center;
|
let ray_dir = pixel_loc - self.look_from;
|
||||||
let r = Ray::new(self.center, ray_dir);
|
let r = Ray::new(self.look_from, ray_dir);
|
||||||
pixel_colour += self.ray_colour(&hittables, &r, self.max_depth);
|
pixel_colour += self.ray_colour(&hittables, &r, self.max_depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,9 +191,9 @@ impl Camera {
|
|||||||
imgbuf.save("output.png").unwrap();
|
imgbuf.save("output.png").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray_colour<T: Hittable>(&self, hittables: &Vec<T>, r: &Ray, depth: u32) -> Colour {
|
fn ray_colour(&self, hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return Colour::nil();
|
return Colour::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
let closest = Hit::hit_list(hittables, r);
|
let closest = Hit::hit_list(hittables, r);
|
||||||
@@ -93,7 +201,7 @@ impl Camera {
|
|||||||
if let Some((scattered, att)) = hit.mat().scatter(&hit, r) {
|
if let Some((scattered, att)) = hit.mat().scatter(&hit, r) {
|
||||||
return att * self.ray_colour(hittables, &scattered, depth - 1);
|
return att * self.ray_colour(hittables, &scattered, depth - 1);
|
||||||
}
|
}
|
||||||
return Colour::nil();
|
return Colour::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
// background
|
// background
|
||||||
|
|||||||
104
src/main.rs
104
src/main.rs
@@ -3,36 +3,110 @@
|
|||||||
mod camera;
|
mod camera;
|
||||||
mod objects;
|
mod objects;
|
||||||
mod ray;
|
mod ray;
|
||||||
|
mod scenes;
|
||||||
mod vec3;
|
mod vec3;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::camera::Camera;
|
|
||||||
use crate::objects::materials::dielectric::Dielectric;
|
use crate::objects::materials::dielectric::Dielectric;
|
||||||
use crate::objects::materials::lambertian::{Lambertian, Metal};
|
use crate::objects::materials::lambertian::{Lambertian, Metal};
|
||||||
|
use crate::objects::materials::traits::Material;
|
||||||
use crate::objects::sphere::Sphere;
|
use crate::objects::sphere::Sphere;
|
||||||
|
use crate::objects::traits::Hittable;
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
|
use crate::scenes::scene::Scene;
|
||||||
use crate::vec3::Vec3;
|
use crate::vec3::Vec3;
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use log::info;
|
||||||
use pretty_env_logger;
|
use pretty_env_logger;
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
use rand::RngExt;
|
||||||
|
|
||||||
|
fn random_material() -> Arc<dyn Material> {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let col = Vec3::new(rng.random(), rng.random(), rng.random());
|
||||||
|
match rng.random_range(0..3) {
|
||||||
|
0 => Arc::new(Lambertian::new(col, 1.)),
|
||||||
|
1 => Arc::new(Metal::new(col, 1., rng.random())),
|
||||||
|
2 => Arc::new(Dielectric::new(rng.random_range(0.3..1.9))),
|
||||||
|
_ => Arc::new(Metal::new(col, 0., rng.random())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_sphere_on_floor<T: Hittable>(
|
||||||
|
materials: &Vec<Arc<dyn Material>>,
|
||||||
|
existing: &Vec<T>,
|
||||||
|
max_size: f32,
|
||||||
|
) -> Sphere {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
let r = rng.random_range(0.1..max_size);
|
||||||
|
let mut sphere = Sphere::xyz(
|
||||||
|
rng.random_range((-50.)..50.),
|
||||||
|
rng.random_range(0.1..max_size),
|
||||||
|
rng.random_range((-50.)..50.),
|
||||||
|
r,
|
||||||
|
materials.choose(&mut rng).unwrap().clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut isct = true;
|
||||||
|
let mut attempts_left = 49;
|
||||||
|
while isct && attempts_left > 0 {
|
||||||
|
isct = false;
|
||||||
|
for h in existing {
|
||||||
|
if h.inside(&h.closest_on_surface(sphere.center())) {
|
||||||
|
info!("Generating sphere failed, {} attempts left", attempts_left);
|
||||||
|
isct = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isct {
|
||||||
|
sphere.set_center(Vec3::new(
|
||||||
|
rng.random_range(0.5..100.),
|
||||||
|
r,
|
||||||
|
rng.random_range(0.5..100.),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
attempts_left -= 1;
|
||||||
|
}
|
||||||
|
sphere
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement scene serialization
|
||||||
fn main() {
|
fn main() {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
// setup objects
|
// TODO: use cli arg for scenefile
|
||||||
let metal = Arc::new(Metal::rgb(0.7, 0.4, 0.2, 1., 0.1));
|
let json_file = "./scenes/scenes.json";
|
||||||
let ground = Arc::new(Lambertian::rgb(0.8, 0.8, 0., 1.0));
|
// let json_file = "./scenes/failsMatBounds.json";
|
||||||
let center = Arc::new(Lambertian::rgb(0.1, 0.2, 0.5, 1.));
|
let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!");
|
||||||
let left = Arc::new(Dielectric::new(1.5));
|
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
|
||||||
let right = Arc::new(Metal::rgb(0.8, 0.6, 0.2, 1., 1.0));
|
scene.render();
|
||||||
|
|
||||||
let mut world = vec![Sphere::xyz(0., 0.5, -0.8, 0.1, metal.clone())];
|
// random spheres code; thought: make this available as cli flag?
|
||||||
world.push(Sphere::xyz(0., -100.5, -1., 100., ground.clone()));
|
// let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.1, 0.2, 0.8))];
|
||||||
world.push(Sphere::xyz(0., 0., -1.2, 0.5, center.clone()));
|
// for i in 0..15 {
|
||||||
world.push(Sphere::xyz(-1., 0., -1.0, 0.5, left.clone()));
|
// info!("Generating {}th material.", i + 1);
|
||||||
world.push(Sphere::xyz(1., 0., -1.0, 0.5, right.clone()));
|
// materials.push(random_material());
|
||||||
|
// }
|
||||||
let c = Camera::new(16. / 9., 800, 2, 50);
|
//
|
||||||
c.render(&world);
|
// let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())];
|
||||||
|
// for i in 0..40 {
|
||||||
|
// info!("Generating {}th sphere.", i + 1);
|
||||||
|
// world.push(random_sphere_on_floor(
|
||||||
|
// &materials,
|
||||||
|
// &world,
|
||||||
|
// ((i + 1) as f32).ln() + (15. as f32).log(10.),
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // let mut c = Camera::new(400, 300);
|
||||||
|
// let mut c = Camera::new(1920, 1080);
|
||||||
|
// c.set_fov(60.);
|
||||||
|
// c.set_anti_alias_rate(1);
|
||||||
|
// c.set_max_depth(10);
|
||||||
|
// c.set_look_from(Vec3::new(-60., 10., 1.));
|
||||||
|
// c.set_look_at(Vec3::new(0., 0., 0.));
|
||||||
|
// c.render(&world);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ impl Hit {
|
|||||||
self.front_face
|
self.front_face
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hit_list<T: Hittable>(hittables: &Vec<T>, r: &Ray) -> Option<Hit> {
|
pub fn hit_list(hittables: &Vec<Arc<dyn Hittable>>, r: &Ray) -> Option<Hit> {
|
||||||
let mut closest: Option<Hit> = None;
|
let mut closest: Option<Hit> = None;
|
||||||
for hittable in hittables {
|
for hittable in hittables {
|
||||||
if let Some(hit) = hittable.hit(r) {
|
if let Some(hit) = hittable.hit(r) {
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
|
use core::f32::math::sqrt;
|
||||||
|
|
||||||
|
use rand::RngExt;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{hit::Hit, materials::traits::Material},
|
objects::{hit::Hit, materials::traits::Material},
|
||||||
ray::Ray,
|
ray::Ray,
|
||||||
vec3::Colour,
|
vec3::{Colour, Vec3},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Dielectric {
|
pub struct Dielectric {
|
||||||
refraction_index: f32,
|
refraction_index: f32,
|
||||||
}
|
}
|
||||||
@@ -14,6 +20,13 @@ impl Dielectric {
|
|||||||
refraction_index: refraction_index,
|
refraction_index: refraction_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _reflectance(cos: f32, refraction_index: f32) -> f32 {
|
||||||
|
// Shlick's approximation
|
||||||
|
let mut r0 = (1. - refraction_index) / (1. + refraction_index);
|
||||||
|
r0 *= r0;
|
||||||
|
return r0 + (1. - r0) * (1. - cos).powf(5.);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Material for Dielectric {
|
impl Material for Dielectric {
|
||||||
@@ -24,7 +37,21 @@ impl Material for Dielectric {
|
|||||||
self.refraction_index
|
self.refraction_index
|
||||||
};
|
};
|
||||||
let unit = ray.dir().get_unit();
|
let unit = ray.dir().get_unit();
|
||||||
let refr = unit.refract(&hit.n().get_unit(), ri);
|
let cos_theta = if -unit.dot(hit.n()) > 1. {
|
||||||
Some((Ray::new(*hit.p(), refr), Colour::new(1., 1., 1.)))
|
1.
|
||||||
|
} else {
|
||||||
|
-unit.dot(hit.n())
|
||||||
|
};
|
||||||
|
let sin_theta = sqrt(1. - cos_theta * cos_theta);
|
||||||
|
let cannot_refract = ri * sin_theta > 1.;
|
||||||
|
|
||||||
|
let dir: Vec3;
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
if cannot_refract || Dielectric::_reflectance(cos_theta, ri) > rng.random::<f32>() {
|
||||||
|
dir = unit.reflect(hit.n());
|
||||||
|
} else {
|
||||||
|
dir = unit.refract(hit.n(), ri);
|
||||||
|
}
|
||||||
|
Some((Ray::new(*hit.p(), dir), Colour::new(1., 1., 1.)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{hit::Hit, materials::traits::Material},
|
objects::{hit::Hit, materials::traits::Material},
|
||||||
@@ -6,6 +7,7 @@ use crate::{
|
|||||||
vec3::{Colour, Vec3},
|
vec3::{Colour, Vec3},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Lambertian {
|
pub struct Lambertian {
|
||||||
albedo: Colour,
|
albedo: Colour,
|
||||||
prob: f32,
|
prob: f32,
|
||||||
@@ -42,6 +44,7 @@ impl Material for Lambertian {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Metal {
|
pub struct Metal {
|
||||||
albedo: Colour,
|
albedo: Colour,
|
||||||
prob: f32,
|
prob: f32,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{objects::hit::Hit, ray::Ray, vec3::Colour};
|
use crate::{objects::hit::Hit, ray::Ray, vec3::Colour};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Material {
|
pub trait Material: Debug {
|
||||||
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)>;
|
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use core::f32::math::sqrt;
|
use core::f32::math::sqrt;
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::objects::hit::Hit;
|
use crate::objects::hit::Hit;
|
||||||
use crate::objects::materials::traits::Material;
|
use crate::objects::materials::traits::Material;
|
||||||
use crate::objects::traits::Hittable;
|
use crate::objects::traits::Hittable;
|
||||||
@@ -13,6 +16,16 @@ pub struct Sphere {
|
|||||||
material: Arc<dyn Material>,
|
material: Arc<dyn Material>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Sphere {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Sphere")
|
||||||
|
.field("center", &self.center)
|
||||||
|
.field("radius", &self.radius)
|
||||||
|
.field("material", &self.material)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Sphere {
|
impl Sphere {
|
||||||
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
|
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -29,6 +42,16 @@ impl Sphere {
|
|||||||
material: mat,
|
material: mat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn center(&self) -> &Vec3 {
|
||||||
|
&self.center
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_center(&mut self, center: Vec3) {
|
||||||
|
if self.center != center {
|
||||||
|
self.center = center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hittable for Sphere {
|
impl Hittable for Sphere {
|
||||||
@@ -60,4 +83,12 @@ impl Hittable for Sphere {
|
|||||||
fn normal_at(&self, p: &Vec3) -> Vec3 {
|
fn normal_at(&self, p: &Vec3) -> Vec3 {
|
||||||
(*p - self.center).get_unit()
|
(*p - self.center).get_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inside(&self, p: &Vec3) -> bool {
|
||||||
|
(*p - self.center).length() < self.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closest_on_surface(&self, p: &Vec3) -> Vec3 {
|
||||||
|
self.normal_at(p) * self.radius
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::objects::hit::Hit;
|
use crate::objects::hit::Hit;
|
||||||
use crate::Ray;
|
use crate::Ray;
|
||||||
use crate::Vec3;
|
use crate::Vec3;
|
||||||
|
|
||||||
pub trait Hittable {
|
pub trait Hittable: Debug {
|
||||||
fn hit(&self, r: &Ray) -> Option<Hit>;
|
fn hit(&self, r: &Ray) -> Option<Hit>;
|
||||||
fn normal_at(&self, p: &Vec3) -> Vec3;
|
fn normal_at(&self, p: &Vec3) -> Vec3;
|
||||||
|
// fn intersect<H: Hittable>(&self, o: &H) -> bool;
|
||||||
|
fn inside(&self, p: &Vec3) -> bool;
|
||||||
|
fn closest_on_surface(&self, p: &Vec3) -> Vec3;
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/scenes.rs
Normal file
2
src/scenes.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod raw_camera;
|
||||||
|
pub mod scene;
|
||||||
57
src/scenes/raw_camera.rs
Normal file
57
src/scenes/raw_camera.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{camera::Camera, vec3::Vec3};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct RawCamera {
|
||||||
|
// output
|
||||||
|
image_width: u32, // TODO: test these are now explicitly required (and that default impl does
|
||||||
|
// not make these optional)
|
||||||
|
image_height: u32,
|
||||||
|
|
||||||
|
// raytracing
|
||||||
|
#[serde(default)]
|
||||||
|
anti_alias_rate: u32,
|
||||||
|
#[serde(default)]
|
||||||
|
max_depth: u32,
|
||||||
|
|
||||||
|
// camera
|
||||||
|
#[serde(default)]
|
||||||
|
fov: f32,
|
||||||
|
#[serde(default)]
|
||||||
|
look_from: Vec3,
|
||||||
|
#[serde(default)]
|
||||||
|
look_at: Vec3,
|
||||||
|
#[serde(default)]
|
||||||
|
vup: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RawCamera {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
image_width: 400,
|
||||||
|
image_height: 300,
|
||||||
|
anti_alias_rate: 1,
|
||||||
|
max_depth: 10,
|
||||||
|
fov: 70.,
|
||||||
|
look_from: Vec3::new(0., 0., 0.),
|
||||||
|
look_at: Vec3::new(0., 0., -1.),
|
||||||
|
vup: Vec3::new(0., 1., 0.),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RawCamera> for Camera {
|
||||||
|
fn from(raw: RawCamera) -> Self {
|
||||||
|
Camera::new_full(
|
||||||
|
raw.image_width,
|
||||||
|
raw.image_height,
|
||||||
|
raw.anti_alias_rate,
|
||||||
|
raw.max_depth,
|
||||||
|
raw.fov,
|
||||||
|
raw.look_from,
|
||||||
|
raw.look_at,
|
||||||
|
raw.vup,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/scenes/scene.rs
Normal file
115
src/scenes/scene.rs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
camera::Camera,
|
||||||
|
objects::{
|
||||||
|
materials::{
|
||||||
|
dielectric::Dielectric,
|
||||||
|
lambertian::{Lambertian, Metal},
|
||||||
|
traits::Material,
|
||||||
|
},
|
||||||
|
sphere::Sphere,
|
||||||
|
traits::Hittable,
|
||||||
|
},
|
||||||
|
scenes::raw_camera::RawCamera,
|
||||||
|
vec3::Vec3,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Scene {
|
||||||
|
pub camera: Camera,
|
||||||
|
pub materials: Vec<Arc<dyn Material>>,
|
||||||
|
pub objects: Vec<Arc<dyn Hittable>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
pub fn render(&mut self) {
|
||||||
|
self.camera.render(&self.objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct SceneDef {
|
||||||
|
pub camera: RawCamera,
|
||||||
|
pub materials: Vec<MaterialDef>,
|
||||||
|
pub objects: Vec<HittableDef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Scene {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let conc = SceneDef::deserialize(deserializer)?;
|
||||||
|
let mats: Vec<Arc<dyn Material>> = conc
|
||||||
|
.materials
|
||||||
|
.into_iter()
|
||||||
|
.map(MaterialDef::into_arc)
|
||||||
|
.collect();
|
||||||
|
let objs: Vec<Arc<dyn Hittable>> = conc
|
||||||
|
.objects
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|h| h.into_arc(&mats))
|
||||||
|
.collect();
|
||||||
|
Ok(Self {
|
||||||
|
camera: Camera::from(conc.camera),
|
||||||
|
materials: mats,
|
||||||
|
objects: objs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct RawSphere {
|
||||||
|
pub center: Vec3,
|
||||||
|
pub radius: f32,
|
||||||
|
pub material: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
|
enum HittableDef {
|
||||||
|
Sphere(RawSphere),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HittableDef {
|
||||||
|
fn into_arc(self, materials: &Vec<Arc<dyn Material>>) -> Option<Arc<dyn Hittable>> {
|
||||||
|
// THOUGHT: i think this can be done better; in the map/filter call up there?
|
||||||
|
match self {
|
||||||
|
HittableDef::Sphere(s) => {
|
||||||
|
if s.material as usize >= materials.len() {
|
||||||
|
warn!(
|
||||||
|
"Sphere specified nonexistent material {}; skipping...",
|
||||||
|
s.material
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Arc::new(Sphere::new(
|
||||||
|
s.center,
|
||||||
|
s.radius,
|
||||||
|
materials.get(s.material as usize).unwrap().clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "type", rename_all = "lowercase")]
|
||||||
|
enum MaterialDef {
|
||||||
|
Lambertian(Lambertian),
|
||||||
|
Metal(Metal),
|
||||||
|
Dielectric(Dielectric),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialDef {
|
||||||
|
fn into_arc(self) -> Arc<dyn Material> {
|
||||||
|
match self {
|
||||||
|
MaterialDef::Lambertian(l) => Arc::new(l),
|
||||||
|
MaterialDef::Metal(m) => Arc::new(m),
|
||||||
|
MaterialDef::Dielectric(d) => Arc::new(d),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
209
src/vec3.rs
209
src/vec3.rs
@@ -1,39 +1,40 @@
|
|||||||
use core::f32::math::sqrt;
|
use core::f32::math::sqrt;
|
||||||
use is_close::default;
|
use is_close::default;
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug, Deserialize)]
|
||||||
pub struct Vec3 {
|
pub struct Vec3 {
|
||||||
r: f32,
|
x: f32,
|
||||||
g: f32,
|
y: f32,
|
||||||
b: f32,
|
z: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Colour = Vec3;
|
pub type Colour = Vec3;
|
||||||
|
|
||||||
impl Vec3 {
|
impl Vec3 {
|
||||||
pub fn new(r: f32, g: f32, b: f32) -> Self {
|
pub fn new(r: f32, g: f32, b: f32) -> Self {
|
||||||
Self { r: r, g: g, b: b }
|
Self { x: r, y: g, z: b }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nil() -> Self {
|
pub fn nil() -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: 0.,
|
x: 0.,
|
||||||
g: 0.,
|
y: 0.,
|
||||||
b: 0.,
|
z: 0.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn random() -> Self {
|
pub fn random() -> Self {
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
Self {
|
Self {
|
||||||
r: rng.random_range(-1.0..1.),
|
x: rng.random_range(-1.0..1.),
|
||||||
g: rng.random_range(-1.0..1.),
|
y: rng.random_range(-1.0..1.),
|
||||||
b: rng.random_range(-1.0..1.),
|
z: rng.random_range(-1.0..1.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,15 +57,15 @@ impl Vec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(&self) -> &f32 {
|
pub fn x(&self) -> &f32 {
|
||||||
&self.r
|
&self.x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn y(&self) -> &f32 {
|
pub fn y(&self) -> &f32 {
|
||||||
&self.g
|
&self.y
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z(&self) -> &f32 {
|
pub fn z(&self) -> &f32 {
|
||||||
&self.b
|
&self.z
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length(&self) -> f32 {
|
pub fn length(&self) -> f32 {
|
||||||
@@ -72,18 +73,18 @@ impl Vec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn length_squared(&self) -> f32 {
|
pub fn length_squared(&self) -> f32 {
|
||||||
(self.r * self.r + self.g * self.g + self.b * self.b) as f32
|
(self.x * self.x + self.y * self.y + self.z * self.z) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dot(&self, other: &Self) -> f32 {
|
pub fn dot(&self, other: &Self) -> f32 {
|
||||||
self.r * other.r + self.g * other.g + self.b * other.b
|
self.x * other.x + self.y * other.y + self.z * other.z
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cross(&self, other: &Self) -> Self {
|
pub fn cross(&self, other: &Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.g * other.b - self.b * other.g,
|
x: self.y * other.z - self.z * other.y,
|
||||||
g: self.b * other.r - self.r * other.b,
|
y: self.z * other.x - self.x * other.z,
|
||||||
b: self.r * other.g - self.g * other.r,
|
z: self.x * other.y - self.y * other.x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +97,9 @@ impl Vec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn near_zero(&self) -> bool {
|
pub fn near_zero(&self) -> bool {
|
||||||
default().is_close(self.r, 0.)
|
default().is_close(self.x, 0.)
|
||||||
&& default().is_close(self.g, 0.)
|
&& default().is_close(self.y, 0.)
|
||||||
&& default().is_close(self.b, 0.)
|
&& default().is_close(self.z, 0.)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reflect(&self, n: &Self) -> Self {
|
pub fn reflect(&self, n: &Self) -> Self {
|
||||||
@@ -117,18 +118,18 @@ impl Vec3 {
|
|||||||
|
|
||||||
pub fn output(self) -> image::Rgb<u8> {
|
pub fn output(self) -> image::Rgb<u8> {
|
||||||
// gamma correction
|
// gamma correction
|
||||||
let r = if self.r > 0. {
|
let r = if self.x > 0. {
|
||||||
sqrt(self.r).clamp(0., 1.)
|
sqrt(self.x).clamp(0., 1.)
|
||||||
} else {
|
} else {
|
||||||
0.
|
0.
|
||||||
};
|
};
|
||||||
let g = if self.g > 0. {
|
let g = if self.y > 0. {
|
||||||
sqrt(self.g).clamp(0., 1.)
|
sqrt(self.y).clamp(0., 1.)
|
||||||
} else {
|
} else {
|
||||||
0.
|
0.
|
||||||
};
|
};
|
||||||
let b = if self.b > 0. {
|
let b = if self.z > 0. {
|
||||||
sqrt(self.b).clamp(0.1, 1.)
|
sqrt(self.z).clamp(0.1, 1.)
|
||||||
} else {
|
} else {
|
||||||
0.
|
0.
|
||||||
};
|
};
|
||||||
@@ -142,9 +143,19 @@ impl Vec3 {
|
|||||||
|
|
||||||
pub fn clone(&self) -> Self {
|
pub fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r,
|
x: self.x,
|
||||||
g: self.g,
|
y: self.y,
|
||||||
b: self.b,
|
z: self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Vec3 {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
x: 0.,
|
||||||
|
y: 0.,
|
||||||
|
z: 0.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,9 +173,9 @@ impl Neg for Vec3 {
|
|||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
Self {
|
Self {
|
||||||
r: -self.r,
|
x: -self.x,
|
||||||
g: -self.g,
|
y: -self.y,
|
||||||
b: -self.b,
|
z: -self.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,9 +185,9 @@ impl Add<Vec3> for Vec3 {
|
|||||||
|
|
||||||
fn add(self, _rhs: Self) -> Self {
|
fn add(self, _rhs: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r + _rhs.r,
|
x: self.x + _rhs.x,
|
||||||
g: self.g + _rhs.g,
|
y: self.y + _rhs.y,
|
||||||
b: self.b + _rhs.b,
|
z: self.z + _rhs.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,9 +197,9 @@ impl Add<f32> for Vec3 {
|
|||||||
|
|
||||||
fn add(self, f: f32) -> Self {
|
fn add(self, f: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r + f,
|
x: self.x + f,
|
||||||
g: self.g + f,
|
y: self.y + f,
|
||||||
b: self.b + f,
|
z: self.z + f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,9 +207,9 @@ impl Add<f32> for Vec3 {
|
|||||||
impl AddAssign<Vec3> for Vec3 {
|
impl AddAssign<Vec3> for Vec3 {
|
||||||
fn add_assign(&mut self, other: Self) {
|
fn add_assign(&mut self, other: Self) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r + other.r,
|
x: self.x + other.x,
|
||||||
g: self.g + other.g,
|
y: self.y + other.y,
|
||||||
b: self.b + other.b,
|
z: self.z + other.z,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,9 +217,9 @@ impl AddAssign<Vec3> for Vec3 {
|
|||||||
impl AddAssign<f32> for Vec3 {
|
impl AddAssign<f32> for Vec3 {
|
||||||
fn add_assign(&mut self, f: f32) {
|
fn add_assign(&mut self, f: f32) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r + f,
|
x: self.x + f,
|
||||||
g: self.g + f,
|
y: self.y + f,
|
||||||
b: self.b + f,
|
z: self.z + f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,9 +228,9 @@ impl Sub<&Vec3> for Vec3 {
|
|||||||
|
|
||||||
fn sub(self, rhs: &Self) -> Self {
|
fn sub(self, rhs: &Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r - rhs.r,
|
x: self.x - rhs.x,
|
||||||
g: self.g - rhs.g,
|
y: self.y - rhs.y,
|
||||||
b: self.b - rhs.b,
|
z: self.z - rhs.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,9 +240,9 @@ impl Sub<Vec3> for Vec3 {
|
|||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self {
|
fn sub(self, rhs: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r - rhs.r,
|
x: self.x - rhs.x,
|
||||||
g: self.g - rhs.g,
|
y: self.y - rhs.y,
|
||||||
b: self.b - rhs.b,
|
z: self.z - rhs.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,9 +252,9 @@ impl Sub<f32> for Vec3 {
|
|||||||
|
|
||||||
fn sub(self, f: f32) -> Self {
|
fn sub(self, f: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r: self.r - f,
|
x: self.x - f,
|
||||||
g: self.g - f,
|
y: self.y - f,
|
||||||
b: self.b - f,
|
z: self.z - f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,9 +262,9 @@ impl Sub<f32> for Vec3 {
|
|||||||
impl SubAssign<Vec3> for Vec3 {
|
impl SubAssign<Vec3> for Vec3 {
|
||||||
fn sub_assign(&mut self, rhs: Self) {
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r - rhs.r,
|
x: self.x - rhs.x,
|
||||||
g: self.g - rhs.g,
|
y: self.y - rhs.y,
|
||||||
b: self.b - rhs.b,
|
z: self.z - rhs.z,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,9 +272,9 @@ impl SubAssign<Vec3> for Vec3 {
|
|||||||
impl SubAssign<f32> for Vec3 {
|
impl SubAssign<f32> for Vec3 {
|
||||||
fn sub_assign(&mut self, f: f32) {
|
fn sub_assign(&mut self, f: f32) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r - f,
|
x: self.x - f,
|
||||||
g: self.g - f,
|
y: self.y - f,
|
||||||
b: self.b - f,
|
z: self.z - f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,9 +284,9 @@ impl Mul<Vec3> for Vec3 {
|
|||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self::Output {
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
Self {
|
Self {
|
||||||
r: self.r * rhs.r,
|
x: self.x * rhs.x,
|
||||||
g: self.g * rhs.g,
|
y: self.y * rhs.y,
|
||||||
b: self.b * rhs.b,
|
z: self.z * rhs.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,9 +297,9 @@ impl Mul<Vec3> for u32 {
|
|||||||
fn mul(self, rhs: Vec3) -> Self::Output {
|
fn mul(self, rhs: Vec3) -> Self::Output {
|
||||||
let f = self as f32;
|
let f = self as f32;
|
||||||
Vec3 {
|
Vec3 {
|
||||||
r: rhs.r * f,
|
x: rhs.x * f,
|
||||||
g: rhs.g * f,
|
y: rhs.y * f,
|
||||||
b: rhs.b * f,
|
z: rhs.z * f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,9 +309,9 @@ impl Mul<f32> for Vec3 {
|
|||||||
|
|
||||||
fn mul(self, f: f32) -> Self::Output {
|
fn mul(self, f: f32) -> Self::Output {
|
||||||
Self {
|
Self {
|
||||||
r: self.r * f,
|
x: self.x * f,
|
||||||
g: self.g * f,
|
y: self.y * f,
|
||||||
b: self.b * f,
|
z: self.z * f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,9 +321,9 @@ impl Mul<Vec3> for f32 {
|
|||||||
|
|
||||||
fn mul(self, rhs: Vec3) -> Self::Output {
|
fn mul(self, rhs: Vec3) -> Self::Output {
|
||||||
Vec3 {
|
Vec3 {
|
||||||
r: rhs.r * self,
|
x: rhs.x * self,
|
||||||
g: rhs.g * self,
|
y: rhs.y * self,
|
||||||
b: rhs.b * self,
|
z: rhs.z * self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,9 +333,9 @@ impl Mul<&Vec3> for f32 {
|
|||||||
|
|
||||||
fn mul(self, rhs: &Vec3) -> Self::Output {
|
fn mul(self, rhs: &Vec3) -> Self::Output {
|
||||||
Vec3 {
|
Vec3 {
|
||||||
r: rhs.r * self,
|
x: rhs.x * self,
|
||||||
g: rhs.g * self,
|
y: rhs.y * self,
|
||||||
b: rhs.b * self,
|
z: rhs.z * self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,9 +343,9 @@ impl Mul<&Vec3> for f32 {
|
|||||||
impl MulAssign<Vec3> for Vec3 {
|
impl MulAssign<Vec3> for Vec3 {
|
||||||
fn mul_assign(&mut self, rhs: Self) {
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r * rhs.r,
|
x: self.x * rhs.x,
|
||||||
g: self.g * rhs.g,
|
y: self.y * rhs.y,
|
||||||
b: self.b * rhs.b,
|
z: self.z * rhs.z,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,9 +353,9 @@ impl MulAssign<Vec3> for Vec3 {
|
|||||||
impl MulAssign<f32> for Vec3 {
|
impl MulAssign<f32> for Vec3 {
|
||||||
fn mul_assign(&mut self, f: f32) {
|
fn mul_assign(&mut self, f: f32) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r * f,
|
x: self.x * f,
|
||||||
g: self.g * f,
|
y: self.y * f,
|
||||||
b: self.b * f,
|
z: self.z * f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,9 +365,9 @@ impl Div<Vec3> for Vec3 {
|
|||||||
|
|
||||||
fn div(self, rhs: Self) -> Self::Output {
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
Self {
|
Self {
|
||||||
r: self.r / rhs.r,
|
x: self.x / rhs.x,
|
||||||
g: self.g / rhs.g,
|
y: self.y / rhs.y,
|
||||||
b: self.b / rhs.b,
|
z: self.z / rhs.z,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,9 +377,9 @@ impl Div<i32> for Vec3 {
|
|||||||
fn div(self, i: i32) -> Self::Output {
|
fn div(self, i: i32) -> Self::Output {
|
||||||
let f: f32 = i as f32;
|
let f: f32 = i as f32;
|
||||||
Self {
|
Self {
|
||||||
r: self.r / f,
|
x: self.x / f,
|
||||||
g: self.g / f,
|
y: self.y / f,
|
||||||
b: self.b / f,
|
z: self.z / f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,9 +389,9 @@ impl Div<f32> for Vec3 {
|
|||||||
|
|
||||||
fn div(self, f: f32) -> Self::Output {
|
fn div(self, f: f32) -> Self::Output {
|
||||||
Self {
|
Self {
|
||||||
r: self.r / f,
|
x: self.x / f,
|
||||||
g: self.g / f,
|
y: self.y / f,
|
||||||
b: self.b / f,
|
z: self.z / f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,9 +399,9 @@ impl Div<f32> for Vec3 {
|
|||||||
impl DivAssign<Vec3> for Vec3 {
|
impl DivAssign<Vec3> for Vec3 {
|
||||||
fn div_assign(&mut self, rhs: Self) {
|
fn div_assign(&mut self, rhs: Self) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r / rhs.r,
|
x: self.x / rhs.x,
|
||||||
g: self.g / rhs.g,
|
y: self.y / rhs.y,
|
||||||
b: self.b / rhs.b,
|
z: self.z / rhs.z,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,21 +409,21 @@ impl DivAssign<Vec3> for Vec3 {
|
|||||||
impl DivAssign<f32> for Vec3 {
|
impl DivAssign<f32> for Vec3 {
|
||||||
fn div_assign(&mut self, f: f32) {
|
fn div_assign(&mut self, f: f32) {
|
||||||
*self = Self {
|
*self = Self {
|
||||||
r: self.r / f,
|
x: self.x / f,
|
||||||
g: self.g / f,
|
y: self.y / f,
|
||||||
b: self.b / f,
|
z: self.z / f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Vec3 {
|
impl PartialEq for Vec3 {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.r == other.r && self.g == other.g && self.b == other.b
|
self.x == other.x && self.y == other.y && self.z == other.z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Vec3 {
|
impl Display for Vec3 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "({}, {}, {})", self.r, self.g, self.b)
|
write!(f, "({}, {}, {})", self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user