Compare commits
1 Commits
master
...
ultraviole
Author | SHA1 | Date | |
---|---|---|---|
7353855119 |
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -12,6 +12,12 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
|
@ -207,6 +213,7 @@ dependencies = [
|
|||
"rand",
|
||||
"rayon",
|
||||
"sdl2",
|
||||
"ultraviolet",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -261,8 +268,26 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "ultraviolet"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae513d44058e41a4669dc336b13a017ea96ad6984bac3797a3d49744e3ffa0ba"
|
||||
dependencies = [
|
||||
"wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528f4316973b7d116d4d87634a4360c97de5d8664352104a130403c32e4b48e8"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
|
|
@ -8,3 +8,4 @@ edition = "2018"
|
|||
sdl2 = "0.33.0"
|
||||
rand = "0.7.3"
|
||||
rayon = "1.3.0"
|
||||
ultraviolet = "0.4.5"
|
||||
|
|
|
@ -39,7 +39,7 @@ fn render(&self, buf: &mut vec<u8>, width: usize, height: usize, samples: u8) {
|
|||
.into_par_iter()
|
||||
.for_each(move |i| {
|
||||
let world = self.world();
|
||||
let camera = self.camera(nx as f64 / ny as f64);
|
||||
let camera = self.camera(nx as f32 / ny as f32);
|
||||
|
||||
let start_y = j * ny;
|
||||
let start_x = i * nx;
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
use {
|
||||
crate::types::{Ray, Vec3},
|
||||
rand::Rng,
|
||||
};
|
||||
use {crate::types::Ray, rand::Rng, ultraviolet::vec::Vec3};
|
||||
|
||||
pub struct Camera {
|
||||
origin: Vec3,
|
||||
horizontal: Vec3,
|
||||
vertical: Vec3,
|
||||
lower_left_corner: Vec3,
|
||||
lens_radius: f64,
|
||||
lens_radius: f32,
|
||||
|
||||
// position vectors
|
||||
u: Vec3,
|
||||
|
@ -26,20 +23,20 @@ impl Camera {
|
|||
look_from: Vec3,
|
||||
look_at: Vec3,
|
||||
v_up: Vec3,
|
||||
vertical_fov: f64,
|
||||
aspect: f64,
|
||||
aperture: f64,
|
||||
focus_distance: f64,
|
||||
vertical_fov: f32,
|
||||
aspect: f32,
|
||||
aperture: f32,
|
||||
focus_distance: f32,
|
||||
) -> Self {
|
||||
// convert degree to radian
|
||||
let angle = vertical_fov * std::f64::consts::PI / 180.0;
|
||||
let angle = vertical_fov * std::f32::consts::PI / 180.0;
|
||||
let half_height = (angle / 2.0).tan();
|
||||
let half_width = aspect * half_height;
|
||||
|
||||
let origin = look_from;
|
||||
let w = (look_from - look_at).unit_vector();
|
||||
let u = v_up.cross(&w).unit_vector();
|
||||
let v = w.cross(&u);
|
||||
let w = (look_from - look_at).normalized();
|
||||
let u = v_up.cross(w).normalized();
|
||||
let v = w.cross(u);
|
||||
|
||||
let lower_left_corner = origin
|
||||
- u * focus_distance * half_width
|
||||
|
@ -61,10 +58,10 @@ impl Camera {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
pub fn get_ray(&self, u: f32, v: f32) -> Ray {
|
||||
let mut rng = rand::thread_rng();
|
||||
let rd = random_in_unit_disk(&mut rng) * self.lens_radius;
|
||||
let offset = self.u * rd.x() + self.v * rd.y();
|
||||
let offset = self.u * rd.x + self.v * rd.y;
|
||||
Ray::new(
|
||||
self.origin + offset,
|
||||
self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin - offset,
|
||||
|
@ -73,10 +70,10 @@ impl Camera {
|
|||
}
|
||||
|
||||
fn random_in_unit_disk(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 1.0, 0.0);
|
||||
let mut p = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), 0.0) * 2.0 - Vec3::new(1.0, 1.0, 0.0);
|
||||
|
||||
while p.dot(&p) >= 1.0 {
|
||||
p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
while p.dot(p) >= 1.0 {
|
||||
p = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
}
|
||||
p
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ use {
|
|||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
Hitable, HitableList, Ray, Sphere,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct DefocusBlur;
|
||||
|
@ -18,7 +19,7 @@ impl Demo for DefocusBlur {
|
|||
}
|
||||
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
let radius = (std::f64::consts::PI / 4.0).cos();
|
||||
let radius = (std::f32::consts::PI / 4.0).cos();
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
|
@ -45,11 +46,11 @@ impl Demo for DefocusBlur {
|
|||
})
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
fn camera(&self, aspect_ratio: f32) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(3.0, 3.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
let aperture = 2.0;
|
||||
let distance_to_focus = (lookfrom - lookat).length();
|
||||
let distance_to_focus = (lookfrom - lookat).mag();
|
||||
let camera = Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
|
@ -88,19 +89,19 @@ impl Demo for DefocusBlur {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ impl Demo for DefocusBlur {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
|
@ -120,8 +121,8 @@ fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ use {
|
|||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
Hitable, HitableList, Ray, Sphere,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct DielectricMaterial;
|
||||
|
@ -75,19 +76,19 @@ impl Demo for DielectricMaterial {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +96,7 @@ impl Demo for DielectricMaterial {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
|
@ -107,8 +108,8 @@ fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
types::{Hitable, HitableList, Ray, Sphere},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct DiffuseMaterials;
|
||||
|
@ -49,13 +50,13 @@ impl Demo for DiffuseMaterials {
|
|||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
let r = camera.get_ray(u, v);
|
||||
color += calc_color(r, &world, &mut rng);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
|
||||
// Without taking square root of each color, we get a picture that
|
||||
// is quite dark
|
||||
|
@ -63,9 +64,9 @@ impl Demo for DiffuseMaterials {
|
|||
// So, IRL, It *should* look a bit lighter in color
|
||||
// To do that, We apply gamma correction by a factor of 2
|
||||
// which means multiple rgb values by 1/gamma aka 1/2
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -73,25 +74,25 @@ impl Demo for DiffuseMaterials {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
// The value of t_min here could've been 0.0 but since f32/f64 can only be
|
||||
// The value of t_min here could've been 0.0 but since f32/f32 can only be
|
||||
// partially compared, It may cause shadow acne effect.
|
||||
// To combat this problem, We set a bias
|
||||
// More information here, https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#shadow-acne
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
let target = hit_rec.p + hit_rec.normal + random_point_in_unit_sphere(rng);
|
||||
calc_color(Ray::new(hit_rec.p, target - hit_rec.p), &world, rng) * 0.5
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
||||
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
let mut point = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), rng.gen::<f32>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
while point.mag_sq() >= 1.0 {
|
||||
point = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), rng.gen::<f32>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
}
|
||||
point
|
||||
|
|
|
@ -3,11 +3,12 @@ use {
|
|||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
Hitable, HitableList, Ray, Sphere,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct FinalScene;
|
||||
|
@ -33,22 +34,22 @@ impl Demo for FinalScene {
|
|||
let l = Vec3::new(4.0, 0.2, 0.0);
|
||||
|
||||
for a in -11..11 {
|
||||
let a = a as f64;
|
||||
let a = a as f32;
|
||||
for b in -11..11 {
|
||||
let b = b as f64;
|
||||
let choose_material_probability = rng.gen::<f64>();
|
||||
let center = Vec3::new(a + 0.9 * rng.gen::<f64>(), 0.2, b + 0.9 * rng.gen::<f64>());
|
||||
let b = b as f32;
|
||||
let choose_material_probability = rng.gen::<f32>();
|
||||
let center = Vec3::new(a + 0.9 * rng.gen::<f32>(), 0.2, b + 0.9 * rng.gen::<f32>());
|
||||
|
||||
if (center - l).length() > 0.9 {
|
||||
if (center - l).mag() > 0.9 {
|
||||
if choose_material_probability < 0.8 {
|
||||
// diffuse material
|
||||
world.push(Box::new(Sphere::with_material(
|
||||
center,
|
||||
radius,
|
||||
Box::new(Lambertian::new(Vec3::new(
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f32>() * rng.gen::<f32>(),
|
||||
rng.gen::<f32>() * rng.gen::<f32>(),
|
||||
rng.gen::<f32>() * rng.gen::<f32>(),
|
||||
))),
|
||||
)));
|
||||
} else if choose_material_probability < 0.95 {
|
||||
|
@ -58,11 +59,11 @@ impl Demo for FinalScene {
|
|||
radius,
|
||||
Box::new(Metal::with_fuzz(
|
||||
Vec3::new(
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f32>()) * 0.5,
|
||||
(1.0 + rng.gen::<f32>()) * 0.5,
|
||||
(1.0 + rng.gen::<f32>()) * 0.5,
|
||||
),
|
||||
0.5 * rng.gen::<f64>(),
|
||||
0.5 * rng.gen::<f32>(),
|
||||
)),
|
||||
)));
|
||||
} else {
|
||||
|
@ -96,7 +97,7 @@ impl Demo for FinalScene {
|
|||
Some(world)
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
fn camera(&self, aspect_ratio: f32) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(13.0, 2.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, 0.0);
|
||||
let camera = Camera::new(
|
||||
|
@ -137,19 +138,19 @@ impl Demo for FinalScene {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +158,7 @@ impl Demo for FinalScene {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
|
@ -169,8 +170,8 @@ fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
Camera,
|
||||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Hitable, HitableList, Ray, Sphere},
|
||||
Camera,
|
||||
},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
pub struct HitableSphere;
|
||||
|
||||
|
@ -45,14 +48,14 @@ impl Demo for HitableSphere {
|
|||
let mut offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let u = i as f64 / x as f64;
|
||||
let v = j as f64 / y as f64;
|
||||
let u = i as f32 / x as f32;
|
||||
let v = j as f32 / y as f32;
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
let color = calc_color(ray, &world);
|
||||
|
||||
buffer[offset] = (255.99 * color.r()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b()) as u8;
|
||||
buffer[offset] = (255.99 * color.x) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -60,19 +63,19 @@ impl Demo for HitableSphere {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f32::MAX) {
|
||||
// It's easier to visualise normals as unit vectors
|
||||
// So, This trick of adding 1 to each dimension and then halving
|
||||
// the resulting value shifts the normals from -1<->1 range to
|
||||
// 0<->1 range
|
||||
Vec3::new(
|
||||
hit_rec.normal.x() + 1.0,
|
||||
hit_rec.normal.y() + 1.0,
|
||||
hit_rec.normal.z() + 1.0,
|
||||
hit_rec.normal.x + 1.0,
|
||||
hit_rec.normal.y + 1.0,
|
||||
hit_rec.normal.z + 1.0,
|
||||
) * 0.5
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = unit_direction.y() * 0.5 + 1.0;
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = unit_direction.y * 0.5 + 1.0;
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
pub struct LinearGradientRectangle;
|
||||
|
||||
use crate::{
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
{demos::Chunk, Demo},
|
||||
use {
|
||||
crate::{
|
||||
types::{HitableList, Ray},
|
||||
Camera,
|
||||
{demos::Chunk, Demo},
|
||||
},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
impl Demo for LinearGradientRectangle {
|
||||
|
@ -38,14 +41,14 @@ impl Demo for LinearGradientRectangle {
|
|||
let mut offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let u = i as f64 / x as f64;
|
||||
let v = j as f64 / y as f64;
|
||||
let u = i as f32 / x as f32;
|
||||
let v = j as f32 / y as f32;
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
|
||||
let c = color(ray);
|
||||
buffer[offset] = (255.99 * c.r()) as u8;
|
||||
buffer[offset + 1] = (255.99 * c.g()) as u8;
|
||||
buffer[offset + 2] = (255.99 * c.b()) as u8;
|
||||
buffer[offset] = (255.99 * c.x) as u8;
|
||||
buffer[offset + 1] = (255.99 * c.y) as u8;
|
||||
buffer[offset + 2] = (255.99 * c.z) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +56,7 @@ impl Demo for LinearGradientRectangle {
|
|||
}
|
||||
|
||||
fn color(ray: Ray) -> Vec3 {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * unit_direction.y() + 1.0;
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * unit_direction.y + 1.0;
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ use {
|
|||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
Hitable, HitableList, Ray, Sphere,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct Materials;
|
||||
|
@ -69,19 +70,19 @@ impl Demo for Materials {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, world.unwrap(), 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ impl Demo for Materials {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
|
@ -101,8 +102,8 @@ fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,16 +25,14 @@ pub use simple_sphere::SimpleSphere;
|
|||
pub use surface_normal_sphere::SurfaceNormalSphere;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
types::{HitableList, Vec3},
|
||||
Camera, HORIZONTAL_PARTITION, VERTICAL_PARTITION,
|
||||
},
|
||||
crate::{types::HitableList, Camera, HORIZONTAL_PARTITION, VERTICAL_PARTITION},
|
||||
rayon::prelude::*,
|
||||
std::{
|
||||
fs::File,
|
||||
io::Write,
|
||||
sync::{Arc, Mutex},
|
||||
},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct Chunk {
|
||||
|
@ -52,7 +50,7 @@ pub trait Demo: std::marker::Sync {
|
|||
let nx = width / VERTICAL_PARTITION;
|
||||
let ny = height / HORIZONTAL_PARTITION;
|
||||
let world = self.world();
|
||||
let camera = self.camera(nx as f64 / ny as f64);
|
||||
let camera = self.camera(nx as f32 / ny as f32);
|
||||
|
||||
let buf = Arc::new(Mutex::new(buf));
|
||||
|
||||
|
@ -93,7 +91,7 @@ pub trait Demo: std::marker::Sync {
|
|||
None
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
fn camera(&self, aspect_ratio: f32) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(0.0, 0.0, 0.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
Some(Camera::new(
|
||||
|
|
|
@ -3,11 +3,12 @@ use {
|
|||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
Hitable, HitableList, Ray, Sphere,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct PositionableCamera;
|
||||
|
@ -18,7 +19,7 @@ impl Demo for PositionableCamera {
|
|||
}
|
||||
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
let radius = (std::f64::consts::PI / 4.0).cos();
|
||||
let radius = (std::f32::consts::PI / 4.0).cos();
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
|
@ -45,7 +46,7 @@ impl Demo for PositionableCamera {
|
|||
})
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
fn camera(&self, aspect_ratio: f32) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(-2.0, 2.0, 1.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
Some(Camera::new(
|
||||
|
@ -84,17 +85,17 @@ impl Demo for PositionableCamera {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
color /= samples as f64;
|
||||
color /= samples as f32;
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
buffer[offset] = (255.99 * color.x.sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y.sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z.sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ impl Demo for PositionableCamera {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f32::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
|
@ -114,8 +115,8 @@ fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = 0.5 * (unit_direction.y + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
types::{Hitable, HitableList, Ray, Sphere},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
pub struct SimpleAntialiasing;
|
||||
|
||||
|
@ -47,16 +48,16 @@ impl Demo for SimpleAntialiasing {
|
|||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
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 u = (i as f32 + rng.gen::<f32>()) / x as f32;
|
||||
let v = (j as f32 + rng.gen::<f32>()) / y as f32;
|
||||
|
||||
let r = camera.get_ray(u, v);
|
||||
color += calc_color(r, world.unwrap());
|
||||
}
|
||||
color /= samples as f64;
|
||||
buffer[offset] = (255.99 * color.r()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b()) as u8;
|
||||
color /= samples as f32;
|
||||
buffer[offset] = (255.99 * color.x) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
@ -64,19 +65,19 @@ impl Demo for SimpleAntialiasing {
|
|||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f64::MAX) {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.0, std::f32::MAX) {
|
||||
// It's easier to visualise normals as unit vectors
|
||||
// So, This trick of adding 1 to each dimension and then halving
|
||||
// the resulting value shifts the normals from -1<->1 range to
|
||||
// 0<->1 range
|
||||
Vec3::new(
|
||||
hit_rec.normal.x() + 1.0,
|
||||
hit_rec.normal.y() + 1.0,
|
||||
hit_rec.normal.z() + 1.0,
|
||||
hit_rec.normal.x + 1.0,
|
||||
hit_rec.normal.y + 1.0,
|
||||
hit_rec.normal.z + 1.0,
|
||||
) * 0.5
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = unit_direction.y() * 0.5 + 1.0;
|
||||
let unit_direction = ray.direction().normalized();
|
||||
let t = unit_direction.y * 0.5 + 1.0;
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ impl Demo for SimpleRectangle {
|
|||
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let color = [i as f64 / x as f64, j as f64 / y as f64, 0.2];
|
||||
let color = [i as f32 / x as f32, j as f32 / y as f32, 0.2];
|
||||
buffer[offset] = (255.99 * color[0]) as u8;
|
||||
buffer[offset + 1] = (255.99 * color[1]) as u8;
|
||||
buffer[offset + 2] = (255.99 * color[2]) as u8;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{HitableList, Ray},
|
||||
Camera,
|
||||
},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
const RADIUS: f64 = 0.5;
|
||||
const RADIUS: f32 = 0.5;
|
||||
|
||||
pub struct SimpleSphere;
|
||||
|
||||
|
@ -51,21 +54,21 @@ impl Demo for SimpleSphere {
|
|||
for i in start_x..start_x + nx {
|
||||
// relative offsets
|
||||
// current position to total width/length
|
||||
let u = i as f64 / x as f64;
|
||||
let v = j as f64 / y as f64;
|
||||
let u = i as f32 / x as f32;
|
||||
let v = j as f32 / y as f32;
|
||||
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
let color = calc_color(ray);
|
||||
buffer[offset] = (255.99 * color.r()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b()) as u8;
|
||||
buffer[offset] = (255.99 * color.x) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.y) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.z) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ray_hit_sphere(center: Vec3, radius: f64, ray: &Ray) -> bool {
|
||||
fn ray_hit_sphere(center: Vec3, radius: f32, ray: &Ray) -> bool {
|
||||
// For a point to lie on a circle,
|
||||
// (x-cx)^2 + (y-cy)^2 + (z-cz)^2 = R * R
|
||||
// should hold true. This equation can be rewritten as,
|
||||
|
@ -81,9 +84,9 @@ fn ray_hit_sphere(center: Vec3, radius: f64, ray: &Ray) -> bool {
|
|||
// Vector from circle center to point
|
||||
let ac = ray.origin() - center;
|
||||
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
let b = 2.0 * ray.direction().dot(&ac);
|
||||
let c = ac.dot(&ac) - radius * radius;
|
||||
let a = ray.direction().dot(ray.direction());
|
||||
let b = 2.0 * ray.direction().dot(ac);
|
||||
let c = ac.dot(ac) - radius * radius;
|
||||
let discriminant = b * b - 4.0 * a * c;
|
||||
|
||||
discriminant > 0.0
|
||||
|
@ -100,10 +103,10 @@ fn calc_color(ray: Ray) -> Vec3 {
|
|||
// This will result in a sphere that is red in color
|
||||
return Vec3::new(1.0, 0.0, 0.0);
|
||||
}
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let unit_direction = ray.direction().normalized();
|
||||
// For rays that don't hit sphere, It'll paint the gradient as the background
|
||||
// Linear gradient depends on y
|
||||
let t = 0.5 * unit_direction.y() + 1.0;
|
||||
let t = 0.5 * unit_direction.y + 1.0;
|
||||
|
||||
// start color + end color
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{HitableList, Ray},
|
||||
Camera,
|
||||
},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
const RADIUS: f64 = 0.5;
|
||||
const RADIUS: f32 = 0.5;
|
||||
pub struct SurfaceNormalSphere;
|
||||
|
||||
impl Demo for SurfaceNormalSphere {
|
||||
|
@ -48,14 +51,14 @@ impl Demo for SurfaceNormalSphere {
|
|||
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let u = i as f64 / x as f64;
|
||||
let v = j as f64 / y as f64;
|
||||
let u = i as f32 / x as f32;
|
||||
let v = j as f32 / y as f32;
|
||||
|
||||
let ray = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||
let color = calculate_color(ray);
|
||||
let ir = (255.99 * color.r()) as u8;
|
||||
let ig = (255.99 * color.g()) as u8;
|
||||
let ib = (255.99 * color.b()) as u8;
|
||||
let ir = (255.99 * color.x) as u8;
|
||||
let ig = (255.99 * color.y) as u8;
|
||||
let ib = (255.99 * color.z) as u8;
|
||||
|
||||
buffer[offset] = ir;
|
||||
buffer[offset + 1] = ig;
|
||||
|
@ -69,23 +72,23 @@ impl Demo for SurfaceNormalSphere {
|
|||
fn calculate_color(ray: Ray) -> Vec3 {
|
||||
let t = ray_hit_sphere(Vec3::new(0.0, 0.0, -1.0), RADIUS, &ray);
|
||||
if t > 0.0 {
|
||||
let n = (ray.point_at_parameter(t) - Vec3::new(0.0, 0.0, -1.0)).unit_vector();
|
||||
return Vec3::new(n.x() + 1.0, n.y() + 1.0, n.z() + 1.0) * 0.5;
|
||||
let n = (ray.point_at_parameter(t) - Vec3::new(0.0, 0.0, -1.0)).normalized();
|
||||
return Vec3::new(n.x + 1.0, n.y + 1.0, n.z + 1.0) * 0.5;
|
||||
}
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let unit_direction = ray.direction().normalized();
|
||||
// For rays that don't hit sphere, It'll paint the gradient as the background
|
||||
// Linear gradient depends on y
|
||||
let t = 0.5 * unit_direction.y() + 1.0;
|
||||
let t = 0.5 * unit_direction.y + 1.0;
|
||||
|
||||
// start color + end color
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
|
||||
fn ray_hit_sphere(center: Vec3, radius: f64, ray: &Ray) -> f64 {
|
||||
fn ray_hit_sphere(center: Vec3, radius: f32, ray: &Ray) -> f32 {
|
||||
let pc = ray.origin() - center;
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
let b = 2.0 * pc.dot(&ray.direction());
|
||||
let c = pc.dot(&pc) - radius * radius;
|
||||
let a = ray.direction().dot(ray.direction());
|
||||
let b = 2.0 * pc.dot(ray.direction());
|
||||
let c = pc.dot(pc) - radius * radius;
|
||||
let discriminant = b * b - 4.0 * a * c;
|
||||
|
||||
if discriminant >= 0.0 {
|
||||
|
|
|
@ -143,7 +143,7 @@ fn main() -> Result<(), String> {
|
|||
println!(
|
||||
"Demo {} Time Taken(s) = {}",
|
||||
active_demo.name(),
|
||||
now.elapsed().as_secs_f64()
|
||||
now.elapsed().as_secs_f32()
|
||||
);
|
||||
|
||||
texture.update(None, &buffer, width * 4).unwrap();
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::types::{Material, Ray, Vec3};
|
||||
use {
|
||||
crate::types::{Material, Ray},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct HitRecord<'a> {
|
||||
/// Rays are represented by A + t * B
|
||||
|
@ -8,7 +11,7 @@ pub struct HitRecord<'a> {
|
|||
/// t is the point at which a ray intersected another object.
|
||||
/// As in, If we put this value of t in A + t * B equation, We'll get the exact
|
||||
/// point at which a ray intersects some other object
|
||||
pub t: f64,
|
||||
pub t: f32,
|
||||
/// Ray object otherwise is represented by the Source/Destination points
|
||||
/// p is what we get when we perform the operation, A + t * B
|
||||
/// i.e. A vector from Ray source to the point t
|
||||
|
@ -22,7 +25,7 @@ pub struct HitRecord<'a> {
|
|||
}
|
||||
|
||||
pub trait Hitable: Send + Sync {
|
||||
fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option<HitRecord> {
|
||||
fn hit(&self, _ray: &Ray, _t_min: f32, _t_max: f32) -> Option<HitRecord> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ pub struct HitableList {
|
|||
}
|
||||
|
||||
impl Hitable for HitableList {
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
fn hit(&self, ray: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let mut closest_so_far = t_max;
|
||||
let mut hit_rec: Option<HitRecord> = None;
|
||||
for obj in &self.list {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::types::{HitRecord, Ray, Vec3},
|
||||
crate::types::{HitRecord, Ray},
|
||||
rand::Rng,
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub trait Material: Send + Sync {
|
||||
|
@ -29,14 +30,14 @@ impl Material for Lambertian {
|
|||
|
||||
pub struct Metal {
|
||||
albedo: Vec3,
|
||||
fuzz: f64,
|
||||
fuzz: f32,
|
||||
}
|
||||
|
||||
impl Metal {
|
||||
pub fn new(albedo: Vec3) -> Self {
|
||||
Self { albedo, fuzz: 0.0 }
|
||||
}
|
||||
pub fn with_fuzz(albedo: Vec3, fuzz: f64) -> Self {
|
||||
pub fn with_fuzz(albedo: Vec3, fuzz: f32) -> Self {
|
||||
Self { albedo, fuzz }
|
||||
}
|
||||
}
|
||||
|
@ -45,13 +46,13 @@ impl Material for Metal {
|
|||
fn scatter(&self, ray_in: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let reflected_ray = reflect(ray_in.direction().unit_vector(), hit_rec.normal);
|
||||
let reflected_ray = reflect(ray_in.direction().normalized(), hit_rec.normal);
|
||||
let scattered_ray = Ray::new(
|
||||
hit_rec.p,
|
||||
reflected_ray + random_point_in_unit_sphere(&mut rng) * self.fuzz,
|
||||
);
|
||||
|
||||
if scattered_ray.direction().dot(&hit_rec.normal) > 0.0 {
|
||||
if scattered_ray.direction().dot(hit_rec.normal) > 0.0 {
|
||||
(self.albedo, Some(scattered_ray))
|
||||
} else {
|
||||
(self.albedo, None)
|
||||
|
@ -60,11 +61,11 @@ impl Material for Metal {
|
|||
}
|
||||
|
||||
pub struct Dielectric {
|
||||
reflection_index: f64,
|
||||
reflection_index: f32,
|
||||
}
|
||||
|
||||
impl Dielectric {
|
||||
pub fn new(reflection_index: f64) -> Self {
|
||||
pub fn new(reflection_index: f32) -> Self {
|
||||
Self { reflection_index }
|
||||
}
|
||||
}
|
||||
|
@ -76,26 +77,25 @@ impl Material for Dielectric {
|
|||
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
|
||||
{
|
||||
let (outward_normal, ni_over_nt, cosine) = if ray_in.direction().dot(hit_rec.normal) > 0.0 {
|
||||
(
|
||||
-hit_rec.normal,
|
||||
self.reflection_index,
|
||||
(ray_in.direction().dot(&hit_rec.normal) * self.reflection_index)
|
||||
/ ray_in.direction().length(),
|
||||
(ray_in.direction().dot(hit_rec.normal) * self.reflection_index)
|
||||
/ ray_in.direction().mag(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
hit_rec.normal,
|
||||
1.0 / self.reflection_index,
|
||||
(-ray_in.direction().dot(&hit_rec.normal)) / ray_in.direction().length(),
|
||||
(-ray_in.direction().dot(hit_rec.normal)) / ray_in.direction().mag(),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(refracted_ray) = refract(ray_in.direction(), outward_normal, ni_over_nt) {
|
||||
let reflect_prob = schlick(cosine, self.reflection_index);
|
||||
|
||||
if rng.gen::<f64>() < reflect_prob {
|
||||
if rng.gen::<f32>() < reflect_prob {
|
||||
(attenuation, Some(Ray::new(hit_rec.p, reflected_ray)))
|
||||
} else {
|
||||
(attenuation, Some(Ray::new(hit_rec.p, refracted_ray)))
|
||||
|
@ -108,20 +108,20 @@ impl Material for Dielectric {
|
|||
|
||||
// Christophe Schlick's Polynomial approximation to figure out reflectivity as the angle changes
|
||||
// See Fresnel Equations, https://en.wikipedia.org/wiki/Fresnel_equations
|
||||
fn schlick(cosine: f64, reflection_index: f64) -> f64 {
|
||||
fn schlick(cosine: f32, reflection_index: f32) -> f32 {
|
||||
let mut r0 = (1.0 - reflection_index) / (1.0 + reflection_index);
|
||||
r0 = r0 * r0;
|
||||
r0 + (1.0 - r0) * (1.0 - cosine).powf(5.0)
|
||||
}
|
||||
|
||||
fn reflect(incident: Vec3, normal: Vec3) -> Vec3 {
|
||||
incident - normal * incident.dot(&normal) * 2.0
|
||||
incident - normal * incident.dot(normal) * 2.0
|
||||
}
|
||||
|
||||
// Snell's Law
|
||||
fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f64) -> Option<Vec3> {
|
||||
let uv = incident.unit_vector();
|
||||
let dt = uv.dot(&normal);
|
||||
fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f32) -> Option<Vec3> {
|
||||
let uv = incident.normalized();
|
||||
let dt = uv.dot(normal);
|
||||
let discriminant = 1.0 - ni_over_nt * ni_over_nt * (1.0 - dt * dt);
|
||||
if discriminant > 0.0 {
|
||||
Some((uv - normal * dt) * ni_over_nt - normal * discriminant.sqrt())
|
||||
|
@ -131,10 +131,10 @@ fn refract(incident: Vec3, normal: Vec3, ni_over_nt: f64) -> Option<Vec3> {
|
|||
}
|
||||
|
||||
fn random_point_in_unit_sphere(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
let mut point = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), rng.gen::<f32>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
while point.sq_len() >= 1.0 {
|
||||
point = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), rng.gen::<f64>()) * 2.0
|
||||
while point.mag_sq() >= 1.0 {
|
||||
point = Vec3::new(rng.gen::<f32>(), rng.gen::<f32>(), rng.gen::<f32>()) * 2.0
|
||||
- Vec3::new(1.0, 1.0, 1.0);
|
||||
}
|
||||
point
|
||||
|
|
|
@ -3,11 +3,9 @@ mod hitable_list;
|
|||
pub mod material;
|
||||
mod ray;
|
||||
mod sphere;
|
||||
mod vec3;
|
||||
|
||||
pub use hitable::{HitRecord, Hitable};
|
||||
pub use hitable_list::HitableList;
|
||||
pub use material::Material;
|
||||
pub use ray::Ray;
|
||||
pub use sphere::Sphere;
|
||||
pub use vec3::Vec3;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::types::Vec3;
|
||||
use ultraviolet::vec::Vec3;
|
||||
|
||||
pub struct Ray {
|
||||
a: Vec3,
|
||||
|
@ -18,7 +18,7 @@ impl Ray {
|
|||
self.b
|
||||
}
|
||||
#[inline]
|
||||
pub fn point_at_parameter(&self, t: f64) -> Vec3 {
|
||||
pub fn point_at_parameter(&self, t: f32) -> Vec3 {
|
||||
self.a + self.b * t
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
use crate::types::{HitRecord, Hitable, Material, Ray, Vec3};
|
||||
use {
|
||||
crate::types::{HitRecord, Hitable, Material, Ray},
|
||||
ultraviolet::vec::Vec3,
|
||||
};
|
||||
|
||||
pub struct Sphere {
|
||||
center: Vec3,
|
||||
radius: f64,
|
||||
radius: f32,
|
||||
material: Option<Box<dyn Material>>,
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(center: Vec3, radius: f64) -> Self {
|
||||
pub fn new(center: Vec3, radius: f32) -> Self {
|
||||
Self {
|
||||
center,
|
||||
radius,
|
||||
material: None,
|
||||
}
|
||||
}
|
||||
pub fn with_material(center: Vec3, radius: f64, material: Box<dyn Material>) -> Self {
|
||||
pub fn with_material(center: Vec3, radius: f32, material: Box<dyn Material>) -> Self {
|
||||
Self {
|
||||
center,
|
||||
radius,
|
||||
|
@ -24,11 +27,11 @@ impl Sphere {
|
|||
}
|
||||
|
||||
impl Hitable for Sphere {
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
fn hit(&self, ray: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||
let oc = ray.origin() - self.center;
|
||||
let a = ray.direction().dot(&ray.direction());
|
||||
let b = oc.dot(&ray.direction());
|
||||
let c = oc.dot(&oc) - self.radius * self.radius;
|
||||
let a = ray.direction().dot(ray.direction());
|
||||
let b = oc.dot(ray.direction());
|
||||
let c = oc.dot(oc) - self.radius * self.radius;
|
||||
|
||||
// The discriminant is calculated using b^2 - 4 * a * c
|
||||
// but in this specific case, If we put the equation in the
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Vec3([f64; 3]);
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
#[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([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]))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user