Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
738e58f2f3 | ||
|
a4aeac2b21 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
target/
|
||||
*.ppm
|
||||
*.png
|
||||
simd.compute
|
||||
|
|
101
Cargo.lock
generated
101
Cargo.lock
generated
|
@ -2,9 +2,9 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
|
@ -12,15 +12,6 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
|
@ -29,24 +20,26 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
||||
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"maybe-uninit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"maybe-uninit",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
@ -63,9 +56,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
|
@ -91,9 +84,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.6"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -106,17 +99,23 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||
checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -129,6 +128,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packed_simd"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
|
@ -146,15 +154,16 @@ dependencies = [
|
|||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"c2-chacha",
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
|
@ -176,6 +185,15 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.3.0"
|
||||
|
@ -204,25 +222,17 @@ dependencies = [
|
|||
name = "ria-weekend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"packed_simd",
|
||||
"rand",
|
||||
"rayon",
|
||||
"sdl2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sdl2"
|
||||
|
@ -246,21 +256,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -4,7 +4,13 @@ version = "0.1.0"
|
|||
authors = ["ishanjain28 <ishanjain28@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
[features]
|
||||
gui = ["sdl2"]
|
||||
avx2 = ["packed_simd"]
|
||||
|
||||
[dependencies]
|
||||
sdl2 = "0.33.0"
|
||||
rand = "0.7.3"
|
||||
sdl2 = { version = "0.33.0", optional = true }
|
||||
rand = { version = "0.7.3", features = ["small_rng"] }
|
||||
rayon = "1.3.0"
|
||||
packed_simd = { version = "0.3.3", optional = true }
|
||||
|
|
|
@ -61,9 +61,8 @@ impl Camera {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
let mut rng = rand::thread_rng();
|
||||
let rd = random_in_unit_disk(&mut rng) * self.lens_radius;
|
||||
pub fn get_ray<R: Rng + ?Sized>(&self, u: f64, v: f64, rng: &mut R) -> Ray {
|
||||
let rd = random_in_unit_disk(rng) * self.lens_radius;
|
||||
let offset = self.u * rd.x() + self.v * rd.y();
|
||||
Ray::new(
|
||||
self.origin + offset,
|
||||
|
@ -72,7 +71,7 @@ impl Camera {
|
|||
}
|
||||
}
|
||||
|
||||
fn random_in_unit_disk(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
fn random_in_unit_disk<R: Rng + ?Sized>(rng: &mut R) -> Vec3 {
|
||||
let mut p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 1.0, 0.0);
|
||||
|
||||
while p.dot(&p) >= 1.0 {
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct DefocusBlur;
|
||||
|
@ -82,6 +82,7 @@ impl Demo for DefocusBlur {
|
|||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -91,8 +92,8 @@ impl Demo for DefocusBlur {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
let ray = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(ray, &world, 0, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
@ -107,14 +108,16 @@ impl Demo for DefocusBlur {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
if let (attenuation, Some(scattered_ray)) =
|
||||
material.unwrap().scatter(&ray, &hit_rec, rng)
|
||||
{
|
||||
calc_color(scattered_ray, &world, depth + 1, rng) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct DielectricMaterial;
|
||||
|
@ -69,6 +69,7 @@ impl Demo for DielectricMaterial {
|
|||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -78,8 +79,8 @@ impl Demo for DielectricMaterial {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
let ray = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(ray, &world, 0, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
@ -94,14 +95,16 @@ impl Demo for DielectricMaterial {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
if let (attenuation, Some(scattered_ray)) =
|
||||
material.unwrap().scatter(&ray, &hit_rec, rng)
|
||||
{
|
||||
calc_color(scattered_ray, &world, depth + 1, rng) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use {
|
|||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct DiffuseMaterials;
|
||||
|
@ -43,7 +43,9 @@ impl Demo for DiffuseMaterials {
|
|||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
|
@ -51,7 +53,7 @@ impl Demo for DiffuseMaterials {
|
|||
for _s in 0..samples {
|
||||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
let r = camera.get_ray(u, v);
|
||||
let r = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(r, &world, &mut rng);
|
||||
}
|
||||
|
||||
|
@ -72,7 +74,7 @@ impl Demo for DiffuseMaterials {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, rng: &mut SmallRng) -> Vec3 {
|
||||
// The value of t_min here could've been 0.0 but since f32/f64 can only be
|
||||
// partially compared, It may cause shadow acne effect.
|
||||
// To combat this problem, We set a bias
|
||||
|
@ -87,7 +89,7 @@ fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) ->
|
|||
}
|
||||
}
|
||||
|
||||
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
fn random_point_in_unit_sphere<R: Rng + ?Sized>(rng: &mut R) -> Vec3 {
|
||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct FinalScene;
|
||||
|
@ -131,6 +131,7 @@ impl Demo for FinalScene {
|
|||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -140,8 +141,8 @@ impl Demo for FinalScene {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
let ray = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(ray, &world, 0, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
@ -156,14 +157,16 @@ impl Demo for FinalScene {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
if let (attenuation, Some(scattered_ray)) =
|
||||
material.unwrap().scatter(&ray, &hit_rec, rng)
|
||||
{
|
||||
calc_color(scattered_ray, &world, depth + 1, rng) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct Materials;
|
||||
|
@ -63,6 +63,7 @@ impl Demo for Materials {
|
|||
let camera = camera.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -72,8 +73,8 @@ impl Demo for Materials {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, world.unwrap(), 0);
|
||||
let ray = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(ray, world.unwrap(), 0, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
@ -88,14 +89,16 @@ impl Demo for Materials {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
if let (attenuation, Some(scattered_ray)) =
|
||||
material.unwrap().scatter(&ray, &hit_rec, rng)
|
||||
{
|
||||
calc_color(scattered_ray, &world, depth + 1, rng) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
|
||||
pub struct PositionableCamera;
|
||||
|
@ -78,6 +78,7 @@ impl Demo for PositionableCamera {
|
|||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -87,8 +88,8 @@ impl Demo for PositionableCamera {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
let ray = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(ray, &world, 0, &mut rng);
|
||||
}
|
||||
color /= samples as f64;
|
||||
// gamma 2 corrected
|
||||
|
@ -101,14 +102,16 @@ impl Demo for PositionableCamera {
|
|||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
if let (attenuation, Some(scattered_ray)) =
|
||||
material.unwrap().scatter(&ray, &hit_rec, rng)
|
||||
{
|
||||
calc_color(scattered_ray, &world, depth + 1, rng) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use {
|
|||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng, SeedableRng},
|
||||
};
|
||||
pub struct SimpleAntialiasing;
|
||||
|
||||
|
@ -41,6 +41,7 @@ impl Demo for SimpleAntialiasing {
|
|||
let camera = camera.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
@ -50,7 +51,7 @@ impl Demo for SimpleAntialiasing {
|
|||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let r = camera.get_ray(u, v);
|
||||
let r = camera.get_ray(u, v, &mut rng);
|
||||
color += calc_color(r, world.unwrap());
|
||||
}
|
||||
color /= samples as f64;
|
||||
|
|
65
src/main.rs
65
src/main.rs
|
@ -6,25 +6,28 @@ mod types;
|
|||
|
||||
pub use camera::Camera;
|
||||
|
||||
use {
|
||||
demos::Demo,
|
||||
sdl2::{
|
||||
event::{Event, WindowEvent},
|
||||
keyboard::Keycode,
|
||||
pixels::PixelFormatEnum,
|
||||
},
|
||||
std::time::Instant,
|
||||
};
|
||||
use {demos::Demo, std::time::Instant};
|
||||
|
||||
const NUM_SAMPLES: u8 = 100;
|
||||
const VERTICAL_PARTITION: usize = 8;
|
||||
const HORIZONTAL_PARTITION: usize = 8;
|
||||
const WIDTH: usize = 800;
|
||||
const HEIGHT: usize = 400;
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
run(WIDTH, HEIGHT)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gui")]
|
||||
fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
||||
use sdl2::{
|
||||
event::{Event, WindowEvent},
|
||||
keyboard::Keycode,
|
||||
pixels::PixelFormatEnum,
|
||||
};
|
||||
|
||||
let sdl_ctx = sdl2::init()?;
|
||||
let video_subsys = sdl_ctx.video()?;
|
||||
let (mut width, mut height): (usize, usize) = (1600, 800);
|
||||
|
||||
let window = video_subsys
|
||||
.window("Ray tracing in a weekend", width as u32, height as u32)
|
||||
.position_centered()
|
||||
|
@ -118,7 +121,6 @@ fn main() -> Result<(), String> {
|
|||
active_demo = &demos::FinalScene;
|
||||
should_update = true;
|
||||
}
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
@ -153,3 +155,42 @@ fn main() -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "gui"))]
|
||||
fn run(width: usize, height: usize) -> Result<(), String> {
|
||||
let mut buffer = vec![0; width * height * 4];
|
||||
let list_of_demos: [Box<dyn Demo>; 12] = [
|
||||
Box::new(demos::SimpleRectangle),
|
||||
Box::new(demos::LinearGradientRectangle),
|
||||
Box::new(demos::SimpleSphere),
|
||||
Box::new(demos::SurfaceNormalSphere),
|
||||
Box::new(demos::HitableSphere),
|
||||
Box::new(demos::SimpleAntialiasing),
|
||||
Box::new(demos::DiffuseMaterials),
|
||||
Box::new(demos::Materials),
|
||||
Box::new(demos::DielectricMaterial),
|
||||
Box::new(demos::PositionableCamera),
|
||||
Box::new(demos::DefocusBlur),
|
||||
Box::new(demos::FinalScene),
|
||||
];
|
||||
for demo in list_of_demos.iter() {
|
||||
println!(
|
||||
"Starting {} at {}x{} with {} samples",
|
||||
demo.name(),
|
||||
width,
|
||||
height,
|
||||
NUM_SAMPLES
|
||||
);
|
||||
let now = Instant::now();
|
||||
demo.render(&mut buffer, width, height, NUM_SAMPLES);
|
||||
println!(
|
||||
"Rendered Demo {}. Time Taken(s) = {}",
|
||||
demo.name(),
|
||||
now.elapsed().as_secs_f64()
|
||||
);
|
||||
|
||||
demo.save_as_ppm(&buffer, width, height);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use {
|
||||
crate::types::{HitRecord, Ray, Vec3},
|
||||
rand::Rng,
|
||||
rand::{rngs::SmallRng, Rng},
|
||||
};
|
||||
|
||||
pub trait Material: Send + Sync {
|
||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>);
|
||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord, rng: &mut SmallRng) -> (Vec3, Option<Ray>);
|
||||
}
|
||||
|
||||
pub struct Lambertian {
|
||||
|
@ -18,9 +18,8 @@ impl Lambertian {
|
|||
}
|
||||
|
||||
impl Material for Lambertian {
|
||||
fn scatter(&self, _ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(&mut rng);
|
||||
fn scatter(&self, _ray: &Ray, hit_rec: &HitRecord, rng: &mut SmallRng) -> (Vec3, Option<Ray>) {
|
||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(rng);
|
||||
let scattered_ray = Ray::new(hit_rec.p, target - hit_rec.p);
|
||||
|
||||
(self.albedo, Some(scattered_ray))
|
||||
|
@ -42,13 +41,16 @@ impl Metal {
|
|||
}
|
||||
|
||||
impl Material for Metal {
|
||||
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
fn scatter(
|
||||
&self,
|
||||
ray_in: &Ray,
|
||||
hit_rec: &HitRecord,
|
||||
rng: &mut SmallRng,
|
||||
) -> (Vec3, Option<Ray>) {
|
||||
let reflected_ray = reflect(ray_in.direction().unit_vector(), hit_rec.normal);
|
||||
let scattered_ray = Ray::new(
|
||||
hit_rec.p,
|
||||
reflected_ray + random_point_in_unit_sphere(&mut rng) * self.fuzz,
|
||||
reflected_ray + random_point_in_unit_sphere(rng) * self.fuzz,
|
||||
);
|
||||
|
||||
if scattered_ray.direction().dot(&hit_rec.normal) > 0.0 {
|
||||
|
@ -70,11 +72,15 @@ impl Dielectric {
|
|||
}
|
||||
|
||||
impl Material for Dielectric {
|
||||
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||
fn scatter(
|
||||
&self,
|
||||
ray_in: &Ray,
|
||||
hit_rec: &HitRecord,
|
||||
rng: &mut SmallRng,
|
||||
) -> (Vec3, Option<Ray>) {
|
||||
let reflected_ray = reflect(ray_in.direction(), hit_rec.normal);
|
||||
// Glass absorbs nothing! So, Attenuation is always going to be 1.0 for this
|
||||
let attenuation = Vec3::new(1.0, 1.0, 1.0);
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let (outward_normal, ni_over_nt, cosine) = if ray_in.direction().dot(&hit_rec.normal) > 0.0
|
||||
{
|
||||
|
@ -130,7 +136,7 @@ fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f64) -> Option<Vec3> {
|
|||
}
|
||||
}
|
||||
|
||||
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
fn random_point_in_unit_sphere<R: Rng + ?Sized>(rng: &mut R) -> Vec3 {
|
||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
|
|
|
@ -6,7 +6,7 @@ pub struct Ray {
|
|||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(a: Vec3, b: Vec3) -> Ray {
|
||||
pub const fn new(a: Vec3, b: Vec3) -> Ray {
|
||||
Ray { a, b }
|
||||
}
|
||||
#[inline]
|
||||
|
|
|
@ -24,6 +24,7 @@ impl Sphere {
|
|||
}
|
||||
|
||||
impl Hitable for Sphere {
|
||||
#[inline]
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let oc = ray.origin() - self.center;
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
|
@ -37,10 +38,10 @@ impl Hitable for Sphere {
|
|||
// Check this for detailed proof
|
||||
// https://vchizhov.github.io/resources/ray%20tracing/ray%20tracing%20tutorial%20series%20vchizhov/ray_casting/part1/intersecting_a_sphere.md.html#appendix
|
||||
let discriminant = b * b - a * c;
|
||||
let discriminant_root = discriminant.sqrt();
|
||||
|
||||
let a_d = 1.0 / a;
|
||||
if discriminant > 0.0 {
|
||||
let root = (-b - discriminant_root) / a;
|
||||
let discriminant_root = discriminant.sqrt();
|
||||
let root = (-b - discriminant_root) * a_d;
|
||||
if root < t_max && root > t_min {
|
||||
let p = ray.point_at_parameter(root);
|
||||
return Some(HitRecord {
|
||||
|
@ -51,7 +52,7 @@ impl Hitable for Sphere {
|
|||
});
|
||||
}
|
||||
|
||||
let root = (-b + discriminant_root) / a;
|
||||
let root = (-b + discriminant_root) * a_d;
|
||||
if root < t_max && root > t_min {
|
||||
let p = ray.point_at_parameter(root);
|
||||
|
||||
|
|
|
@ -1,192 +1,418 @@
|
|||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||
};
|
||||
#[cfg(feature = "avx2")]
|
||||
pub use avx2::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Vec3([f64; 3]);
|
||||
#[cfg(not(feature = "avx2"))]
|
||||
pub use scalar::*;
|
||||
|
||||
impl Vec3 {
|
||||
#[inline]
|
||||
pub const fn new(a: f64, b: f64, c: f64) -> Vec3 {
|
||||
Vec3([a, b, c])
|
||||
}
|
||||
#[inline]
|
||||
pub fn x(&self) -> f64 {
|
||||
self[0]
|
||||
}
|
||||
#[inline]
|
||||
pub fn y(&self) -> f64 {
|
||||
self[1]
|
||||
}
|
||||
#[inline]
|
||||
pub fn z(&self) -> f64 {
|
||||
self[2]
|
||||
}
|
||||
#[inline]
|
||||
pub fn r(&self) -> f64 {
|
||||
self[0]
|
||||
}
|
||||
#[inline]
|
||||
pub fn g(&self) -> f64 {
|
||||
self[1]
|
||||
}
|
||||
#[inline]
|
||||
pub fn b(&self) -> f64 {
|
||||
self[2]
|
||||
#[cfg(feature = "avx2")]
|
||||
mod avx2 {
|
||||
#[cfg(feature = "avx2")]
|
||||
use packed_simd::f64x4;
|
||||
|
||||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||
};
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct Vec3(f64x4);
|
||||
|
||||
impl Vec3 {
|
||||
#[inline]
|
||||
pub const fn new(a: f64, b: f64, c: f64) -> Vec3 {
|
||||
Vec3(f64x4::new(a, b, c, 0.0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn x(&self) -> f64 {
|
||||
self.0.extract(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn y(&self) -> f64 {
|
||||
self.0.extract(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn z(&self) -> f64 {
|
||||
self.0.extract(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn r(&self) -> f64 {
|
||||
self.0.extract(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn g(&self) -> f64 {
|
||||
self.0.extract(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn b(&self) -> f64 {
|
||||
self.0.extract(2)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn length(&self) -> f64 {
|
||||
self.sq_len().sqrt()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sq_len(&self) -> f64 {
|
||||
let p = self.0.powf(f64x4::new(2.0, 2.0, 2.0, 2.0));
|
||||
p.sum()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dot(&self, v: &Vec3) -> f64 {
|
||||
let p = self.0 * v.0;
|
||||
p.sum()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cross(&self, v: &Vec3) -> Vec3 {
|
||||
let p1 = self.0 * f64x4::new(v.0.extract(1), v.0.extract(2), v.0.extract(0), 0.0);
|
||||
let p2 = self.0 * f64x4::new(v.0.extract(2), v.0.extract(0), v.0.extract(1), 0.0);
|
||||
|
||||
Vec3(f64x4::new(
|
||||
p1.extract(1) - p2.extract(2),
|
||||
p1.extract(2) - p2.extract(0),
|
||||
p1.extract(0) - p2.extract(1),
|
||||
0.0,
|
||||
))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unit_vector(&self) -> Vec3 {
|
||||
let length = self.length();
|
||||
Vec3(self.0 / length)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn length(&self) -> f64 {
|
||||
self.sq_len().sqrt()
|
||||
impl Add for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn add(self, o: Vec3) -> Vec3 {
|
||||
Vec3(self.0 + o.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sq_len(&self) -> f64 {
|
||||
self[0] * self[0] + self[1] * self[1] + self[2] * self[2]
|
||||
impl AddAssign for Vec3 {
|
||||
fn add_assign(&mut self, o: Vec3) {
|
||||
self.0 += o.0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dot(&self, v: &Vec3) -> f64 {
|
||||
self[0] * v[0] + self[1] * v[1] + self[2] * v[2]
|
||||
impl Sub for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn sub(self, o: Vec3) -> Vec3 {
|
||||
Vec3(self.0 - o.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cross(&self, v: &Vec3) -> Vec3 {
|
||||
Vec3([
|
||||
self[1] * v[2] - self[2] * v[1],
|
||||
self[2] * v[0] - self[0] * v[2],
|
||||
self[0] * v[1] - self[1] * v[0],
|
||||
])
|
||||
impl SubAssign for Vec3 {
|
||||
fn sub_assign(&mut self, o: Vec3) {
|
||||
self.0 -= o.0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn make_unit_vector(&mut self) {
|
||||
let k = 1.0f64 / (self[0] * self[0] + self[1] * self[1] + self[2] * self[2]);
|
||||
self[0] *= k;
|
||||
self[1] *= k;
|
||||
self[2] *= k;
|
||||
impl Neg for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn neg(self) -> Vec3 {
|
||||
Vec3(-self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unit_vector(&self) -> Vec3 {
|
||||
let length = self.length();
|
||||
Vec3([self[0] / length, self[1] / length, self[2] / length])
|
||||
impl MulAssign<Vec3> for Vec3 {
|
||||
fn mul_assign(&mut self, o: Vec3) {
|
||||
self.0 *= o.0
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, o: f64) {
|
||||
self.0 *= o
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: f64) -> Vec3 {
|
||||
Vec3(self.0 * o)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: Vec3) -> Vec3 {
|
||||
Vec3(self.0 * o.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: Vec3) -> Vec3 {
|
||||
Vec3(self.0 / o.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: f64) -> Vec3 {
|
||||
let o = 1.0 / o;
|
||||
self * o
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f64> for Vec3 {
|
||||
fn div_assign(&mut self, o: f64) {
|
||||
let o = 1.0 / o;
|
||||
*self *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
f.write_fmt(format_args!(
|
||||
"{} {} {}",
|
||||
self.0.extract(0),
|
||||
self.0.extract(1),
|
||||
self.0.extract(2)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vec3_test() {
|
||||
let v = Vec3::new(0.5, 0.6, 0.8);
|
||||
let q = Vec3::new(0.4, 0.2, 0.1);
|
||||
let cross = Vec3::new(
|
||||
-0.10000000000000003,
|
||||
0.2700000000000001,
|
||||
-0.13999999999999999,
|
||||
);
|
||||
let unit_vector = Vec3::new(0.4472135954999579, 0.5366563145999494, 0.7155417527999327);
|
||||
let add = Vec3::new(0.9, 0.8, 0.9);
|
||||
let sub = Vec3::new(0.09999999999999998, 0.39999999999999997, 0.7000000000000001);
|
||||
let mul = Vec3::new(0.2, 0.12, 0.08000000000000002);
|
||||
let div = Vec3::new(1.25, 2.9999999999999996, 8.0);
|
||||
|
||||
assert_eq!(v.x(), 0.5);
|
||||
assert_eq!(v.y(), 0.6);
|
||||
assert_eq!(v.z(), 0.8);
|
||||
assert_eq!(v.r(), 0.5);
|
||||
assert_eq!(v.g(), 0.6);
|
||||
assert_eq!(v.b(), 0.8);
|
||||
assert_eq!(v.length(), 1.118033988749895);
|
||||
assert_eq!(v.sq_len(), 1.25);
|
||||
assert_eq!(v.dot(&q), 0.4);
|
||||
assert_eq!(v.cross(&q), cross);
|
||||
assert_eq!(v.unit_vector(), unit_vector);
|
||||
assert_eq!(v + q, add);
|
||||
assert_eq!(v - q, sub);
|
||||
assert_eq!(v * q, mul);
|
||||
assert_eq!(v / q, div);
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Vec3 {
|
||||
type Output = Vec3;
|
||||
mod scalar {
|
||||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||
};
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct Vec3(f64, f64, f64);
|
||||
|
||||
fn add(self, o: Vec3) -> Vec3 {
|
||||
Vec3([self[0] + o[0], self[1] + o[1], self[2] + o[2]])
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Vec3 {
|
||||
fn add_assign(&mut self, o: Vec3) {
|
||||
self.0[0] += o.0[0];
|
||||
self.0[1] += o.0[1];
|
||||
self.0[2] += o.0[2];
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn sub(self, o: Vec3) -> Vec3 {
|
||||
Vec3([self[0] - o[0], self[1] - o[1], self[2] - o[2]])
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Vec3 {
|
||||
fn sub_assign(&mut self, o: Vec3) {
|
||||
self[0] -= o[0];
|
||||
self[1] -= o[1];
|
||||
self[2] -= o[2];
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn neg(self) -> Vec3 {
|
||||
Vec3([-self[0], -self[1], -self[2]])
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<Vec3> for Vec3 {
|
||||
fn mul_assign(&mut self, o: Vec3) {
|
||||
self[0] *= o[0];
|
||||
self[1] *= o[1];
|
||||
self[2] *= o[2];
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, o: f64) {
|
||||
self[0] *= o;
|
||||
self[1] *= o;
|
||||
self[2] *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: f64) -> Vec3 {
|
||||
Vec3([self[0] * o, self[1] * o, self[2] * o])
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: Vec3) -> Vec3 {
|
||||
Vec3([self[0] * o[0], self[1] * o[1], self[2] * o[2]])
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: Vec3) -> Vec3 {
|
||||
Vec3([self[0] / o[0], self[1] / o[1], self[2] / o[2]])
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: f64) -> Vec3 {
|
||||
let o = 1.0 / o;
|
||||
Vec3([self[0] * o, self[1] * o, self[2] * o])
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f64> for Vec3 {
|
||||
fn div_assign(&mut self, o: f64) {
|
||||
let o = 1.0 / o;
|
||||
self.0[0] *= o;
|
||||
self.0[1] *= o;
|
||||
self.0[2] *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Vec3 {
|
||||
type Output = f64;
|
||||
|
||||
fn index(&self, q: usize) -> &f64 {
|
||||
&self.0[q]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Vec3 {
|
||||
fn index_mut(&mut self, q: usize) -> &mut f64 {
|
||||
&mut self.0[q]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
f.write_fmt(format_args!("{} {} {}", self[0], self[1], self[2]))
|
||||
impl Vec3 {
|
||||
#[inline]
|
||||
pub const fn new(a: f64, b: f64, c: f64) -> Vec3 {
|
||||
Vec3(a, b, c)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn x(&self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
#[inline]
|
||||
pub fn y(&self) -> f64 {
|
||||
self.1
|
||||
}
|
||||
#[inline]
|
||||
pub fn z(&self) -> f64 {
|
||||
self.2
|
||||
}
|
||||
#[inline]
|
||||
pub fn r(&self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
#[inline]
|
||||
pub fn g(&self) -> f64 {
|
||||
self.1
|
||||
}
|
||||
#[inline]
|
||||
pub fn b(&self) -> f64 {
|
||||
self.2
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn length(&self) -> f64 {
|
||||
self.sq_len().sqrt()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sq_len(&self) -> f64 {
|
||||
self.0 * self.0 + self.1 * self.1 + self.2 * self.2
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dot(&self, v: &Vec3) -> f64 {
|
||||
self.0 * v.0 + self.1 * v.1 + self.2 * v.2
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cross(&self, v: &Vec3) -> Vec3 {
|
||||
Vec3(
|
||||
self.1 * v.2 - self.2 * v.1,
|
||||
self.2 * v.0 - self.0 * v.2,
|
||||
self.0 * v.1 - self.1 * v.0,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unit_vector(&self) -> Vec3 {
|
||||
let length = self.length();
|
||||
Vec3(self.0 / length, self.1 / length, self.2 / length)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn add(self, o: Vec3) -> Vec3 {
|
||||
Vec3::new(self.0 + o.0, self.1 + o.1, self.2 + o.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Vec3 {
|
||||
fn add_assign(&mut self, o: Vec3) {
|
||||
self.0 += o.0;
|
||||
self.1 += o.1;
|
||||
self.2 += o.2;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn sub(self, o: Vec3) -> Vec3 {
|
||||
Vec3::new(self.0 - o.0, self.1 - o.1, self.2 - o.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Vec3 {
|
||||
fn sub_assign(&mut self, o: Vec3) {
|
||||
self.0 -= o.0;
|
||||
self.1 -= o.1;
|
||||
self.2 -= o.2;
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn neg(self) -> Vec3 {
|
||||
Vec3(-self.0, -self.1, -self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<Vec3> for Vec3 {
|
||||
fn mul_assign(&mut self, o: Vec3) {
|
||||
self.0 *= o.0;
|
||||
self.1 *= o.1;
|
||||
self.2 *= o.2;
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, o: f64) {
|
||||
self.0 *= o;
|
||||
self.1 *= o;
|
||||
self.2 *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: f64) -> Vec3 {
|
||||
Vec3::new(self.0 * o, self.1 * o, self.2 * o)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
fn mul(self, o: Vec3) -> Vec3 {
|
||||
Vec3::new(self.0 * o.0, self.1 * o.1, self.2 * o.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Vec3> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: Vec3) -> Vec3 {
|
||||
Vec3::new(self.0 / o.0, self.1 / o.1, self.2 / o.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Vec3 {
|
||||
type Output = Vec3;
|
||||
|
||||
fn div(self, o: f64) -> Vec3 {
|
||||
let o = 1.0 / o;
|
||||
self * o
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f64> for Vec3 {
|
||||
fn div_assign(&mut self, o: f64) {
|
||||
let o = 1.0 / o;
|
||||
*self *= o;
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Vec3 {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
f.write_fmt(format_args!("{} {} {}", self.0, self.1, self.2))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vec3_test() {
|
||||
let v = Vec3::new(0.5, 0.6, 0.8);
|
||||
let q = Vec3::new(0.4, 0.2, 0.1);
|
||||
let cross = Vec3::new(
|
||||
-0.10000000000000003,
|
||||
0.2700000000000001,
|
||||
-0.13999999999999999,
|
||||
);
|
||||
let unit_vector = Vec3::new(0.4472135954999579, 0.5366563145999494, 0.7155417527999327);
|
||||
let add = Vec3::new(0.9, 0.8, 0.9);
|
||||
let sub = Vec3::new(0.09999999999999998, 0.39999999999999997, 0.7000000000000001);
|
||||
let mul = Vec3::new(0.2, 0.12, 0.08000000000000002);
|
||||
let div = Vec3::new(1.25, 2.9999999999999996, 8.0);
|
||||
|
||||
assert_eq!(v.x(), 0.5);
|
||||
assert_eq!(v.y(), 0.6);
|
||||
assert_eq!(v.z(), 0.8);
|
||||
assert_eq!(v.r(), 0.5);
|
||||
assert_eq!(v.g(), 0.6);
|
||||
assert_eq!(v.b(), 0.8);
|
||||
assert_eq!(v.length(), 1.118033988749895);
|
||||
assert_eq!(v.sq_len(), 1.25);
|
||||
assert_eq!(v.dot(&q), 0.4);
|
||||
assert_eq!(v.cross(&q), cross);
|
||||
assert_eq!(v.unit_vector(), unit_vector);
|
||||
assert_eq!(v + q, add);
|
||||
assert_eq!(v - q, sub);
|
||||
assert_eq!(v * q, mul);
|
||||
assert_eq!(v / q, div);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user