Compare commits

..

No commits in common. "388c48d236012649730f6f6e62ea0f9ab6aeb20c" and "89a2333644a82f2645e4ad554eadf7d4f142f2c0" have entirely different histories.

7 changed files with 84 additions and 120 deletions

1
.gitignore vendored
View File

@ -2,4 +2,3 @@
*.ppm *.ppm
.idea .idea
*.iml *.iml
.vscode/

View File

@ -4,56 +4,42 @@ pub struct Camera {
aspect_ratio: f64, aspect_ratio: f64,
viewport_height: f64, viewport_height: f64,
viewport_width: f64, viewport_width: f64,
focal_length: f64,
origin: Point3, origin: Point3,
horizontal: Vec3, horizontal: Vec3,
vertical: Vec3, vertical: Vec3,
lower_left_corner: Vec3, lower_left_corner: Vec3
lens_radius: f64,
u: Vec3,
v: Vec3,
w: Vec3
} }
impl Camera { impl Camera {
pub fn get_ray(&self, s: f64, t: f64) -> Ray { pub fn get_ray(&self, u: f64, v: f64) -> Ray {
let rd = self.lens_radius * Vec3::random_unit_disk();
let offset = self.u * rd.x() + self.v * rd.y();
Ray::new( Ray::new(
self.origin + offset, self.origin,
self.lower_left_corner + s*self.horizontal + t*self.vertical - self.origin - offset) self.lower_left_corner + u*self.horizontal + v*self.vertical - self.origin)
} }
pub fn new( pub fn new(aspect_ratio: f64) -> Self {
look_from: Point3, let viewport_height = 2.0;
look_at: Point3,
up: Vec3,
aspect_ratio: f64,
vfov: f64,
aperture: f64,
focus_dist: f64) -> Self {
let theta = vfov.to_radians();
let h = (theta / 2.0).tan();
let viewport_height = 2.0 * h;
let viewport_width = aspect_ratio * viewport_height; let viewport_width = aspect_ratio * viewport_height;
let origin = Point3::default();
let w = (look_from - look_at).unit_vector(); let horizontal = Vec3::new(viewport_width, 0.0, 0.0);
let u = up.cross(&w).unit_vector(); let vertical = Vec3::new(0.0, viewport_height, 0.0);
let v = w.cross(&u); let focal_length = 1.0;
let horizontal = focus_dist * viewport_width * u;
let vertical = focus_dist * viewport_height * v;
Camera { Camera {
aspect_ratio, aspect_ratio,
viewport_height, viewport_height,
viewport_width, viewport_width,
origin: look_from, focal_length,
origin,
horizontal, horizontal,
vertical, vertical,
lower_left_corner: look_from - horizontal/2.0 - vertical/2.0 - focus_dist*w, lower_left_corner: origin - horizontal/2.0 - vertical/2.0 - Vec3::new(0.0, 0.0, focal_length)
lens_radius: aperture / 2.0,
u,
v,
w
} }
} }
} }
impl Default for Camera {
fn default() -> Self {
let aspect_ratio = 16.0 / 9.0;
Camera::new(aspect_ratio)
}
}

View File

@ -42,16 +42,16 @@ impl Hittable for Sphere {
let discriminant = half_b * half_b - a * c; let discriminant = half_b * half_b - a * c;
if discriminant < 0.0 { return None; } if discriminant < 0.0 { return None; }
let sqrtd = discriminant.sqrt(); let sqrtd = f64::sqrt(discriminant);
let mut root = (-half_b - sqrtd) / a; let root = (-half_b - sqrtd) / a;
if root < t_min || t_max < root { if root < t_min || t_max < root {
root = (-half_b + sqrtd) / a; let root = (-half_b + sqrtd) / a;
if root < t_min || t_max < root { return None; } if root < t_min || t_max < root { return None; }
} }
let point = ray.at(root); let point = ray.at(root);
let normal = (point - self.center) / self.radius; let normal = (point - self.center) / self.radius;
let dot = ray.direction().dot(&normal); let front_face = ray.direction().dot(&normal) < 0.0;
let front_face = dot < 0.0;
let normal = if front_face { normal } else { -normal }; let normal = if front_face { normal } else { -normal };
Some(HitRecord { Some(HitRecord {
point, point,

View File

@ -8,79 +8,59 @@ use crate::material::{Dielectric, Lambertian, Material, Metal};
mod vec3; mod vec3;
mod ray; mod ray;
mod hittable; mod hittable;
mod material;
mod camera; mod camera;
mod material;
fn random_scene() -> Vec<Box<dyn Hittable>> {
let mut world:Vec<Box<dyn Hittable>> = Vec::new();
let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
let ground = Sphere {
center: Point3::new(0.0, -1000.0, 0.0),
radius: 1000.0,
material: material_ground
};
world.push(Box::new(ground));
let unit_range = Uniform::from(0.0..1.0);
let fuzz_range = Uniform::from(0.0..0.5);
let mut rng = rand::thread_rng();
let p = Point3::new(4.0, 0.2, 0.0);
for a in -1..11 {
for b in -11..11 {
let choose_material = unit_range.sample(&mut rng);
let center = Point3::new(
(a as f64) + 0.9*unit_range.sample(&mut rng),
0.2,
(b as f64) + 0.9*unit_range.sample(&mut rng));
if (center - p).length() < 0.9 {
continue;
}
let material = match choose_material {
_ if choose_material < 0.8 => Material::Lambertian(Lambertian::new(
Color::random(0.0, 1.0) * Color::random(0.0, 1.0))),
_ if choose_material < 0.95 => Material::Metal(Metal::new(
Color::random(0.5, 1.0),
fuzz_range.sample(&mut rng))),
_ => Material::Dielectric(Dielectric::new(1.5)),
};
let sphere = Box::new(Sphere {
center,
radius: 0.2,
material
});
world.push(sphere);
}
}
world
}
fn main() { fn main() {
// Image // Image
const ASPECT_RATIO: f64 = 3.0 / 2.0; const ASPECT_RATIO: f64 = 16.0 / 9.0;
const IMAGE_WIDTH: i32 = 1200; const IMAGE_WIDTH: i32 = 400;
const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32; const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32;
const SAMPLES_PER_PIXEL: i32 = 10; const SAMPLES_PER_PIXEL: i32 = 10;
const MAX_DEPTH: i32 = 50; const MAX_DEPTH: i32 = 50;
let look_from = Point3::new(13.0, 2.0, 3.0);
let look_at = Point3::new(0.0, 0.0, 0.0);
let focus_dist = 10.0;
// Camera // Camera
let cam = Camera::new( let cam = Camera::new(ASPECT_RATIO);
look_from,
look_at,
Vec3::new(0.0, 1.0, 0.0),
ASPECT_RATIO,
20.0,
0.1,
focus_dist);
// World // World
let world= random_scene(); let mut world:Vec<Box<dyn Hittable>> = Vec::new();
let center = Box::new(Sphere {
center: Point3::new(0.0, 0.0, -1.0),
radius: 0.5,
material: Material::Lambertian(Lambertian::new(Color::new(0.7, 0.3, 0.3)))
});
let center_glass = Box::new(Sphere {
center: Point3::new(0.0, 0.0, -1.0),
radius: 0.5,
material: Material::Dielectric(Dielectric::new(1.5))
});
world.push(center_glass);
let ground = Sphere {
center: Point3::new(0.0, -100.5, -1.0),
radius: 100.0,
material: Material::Lambertian(Lambertian::new(Color::new(0.8, 0.8, 0.0)))
};
world.push(Box::new(ground));
let left = Box::new(Sphere {
center: Point3::new(-1.0, 0.0, -1.0),
radius: 0.5,
material: Material::Metal(Metal::new(Color::new(0.8, 0.8, 0.8), 0.3))
});
let left_glass = Box::new(Sphere {
center: Point3::new(-1.0, 0.0, -1.0),
radius: 0.5,
material: Material::Dielectric(Dielectric::new(1.5))
});
world.push(left_glass);
let right = Box::new(Sphere {
center: Point3::new(1.0, 0.0, -1.0),
radius: 0.5,
material: Material::Metal(Metal::new(Color::new(0.8, 0.6, 0.2), 1.0))
});
world.push(right);
println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT);
let between = Uniform::from(0.0..1.0); let between = Uniform::from(0.0..1.0);
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
for j in (0..IMAGE_HEIGHT).rev() { for j in (0..IMAGE_HEIGHT).rev() {
@ -92,9 +72,6 @@ fn main() {
let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
let ray = cam.get_ray(u, v); let ray = cam.get_ray(u, v);
if i == 200 && (j == 112 || j == 113) {
let tt = 0;
}
color += ray.pixel_color(&world, MAX_DEPTH); color += ray.pixel_color(&world, MAX_DEPTH);
} }
color.write_color(SAMPLES_PER_PIXEL); color.write_color(SAMPLES_PER_PIXEL);

View File

@ -104,7 +104,6 @@ impl Scatterable for Dielectric {
self.index_of_refraction self.index_of_refraction
}; };
let unit_direction = ray.direction().unit_vector(); let unit_direction = ray.direction().unit_vector();
let cos_theta = ((-unit_direction).dot(&hit_record.normal)).min(1.0); let cos_theta = ((-unit_direction).dot(&hit_record.normal)).min(1.0);
let sin_theta = (1.0 - cos_theta*cos_theta).sqrt(); let sin_theta = (1.0 - cos_theta*cos_theta).sqrt();
let cannot_refract = refraction_ratio * sin_theta > 1.0; let cannot_refract = refraction_ratio * sin_theta > 1.0;
@ -113,10 +112,12 @@ impl Scatterable for Dielectric {
if cannot_refract || reflectance > rng.gen::<f64>() { if cannot_refract || reflectance > rng.gen::<f64>() {
let reflected = unit_direction.reflected(&hit_record.normal); let reflected = unit_direction.reflected(&hit_record.normal);
let reflected = Vec3::new(-reflected.x(), reflected.y(), -reflected.z());
let scattered = Ray::new(hit_record.point, reflected); let scattered = Ray::new(hit_record.point, reflected);
Some((Some(scattered), color)) Some((Some(scattered), color))
} else { } else {
let direction = unit_direction.refract(&hit_record.normal, refraction_ratio); //let direction = unit_direction.refract(&hit_record.normal, refraction_ratio);
let direction = unit_direction.refract_sort_of_works(&hit_record.normal, refraction_ratio);
let scattered = Ray::new(hit_record.point, direction); let scattered = Ray::new(hit_record.point, direction);
Some((Some(scattered), color)) Some((Some(scattered), color))
} }

View File

@ -3,7 +3,6 @@ use crate::hittable::HitRecord;
use crate::material::Scatterable; use crate::material::Scatterable;
use crate::vec3::Point3; use crate::vec3::Point3;
#[derive(Debug)]
pub struct Ray { pub struct Ray {
origin: Point3, origin: Point3,
direction: Vec3 direction: Vec3

View File

@ -63,19 +63,6 @@ impl Vec3 {
} }
} }
pub fn random_unit_vector() -> Self { Vec3::random_in_unit_sphere().unit_vector() } pub fn random_unit_vector() -> Self { Vec3::random_in_unit_sphere().unit_vector() }
pub fn random_unit_disk() -> Self {
let between = Uniform::from(-1.0..1.0);
let mut rng = rand::thread_rng();
loop {
let v = Vec3::new(
between.sample(&mut rng),
between.sample(&mut rng),
0.0);
if v.length_squared() < 1.0 {
return v;
}
}
}
pub fn near_zero(&self) -> bool { pub fn near_zero(&self) -> bool {
const MAXIMUM_DISTANCE_FROM_ZERO:f64 = 1e-8; const MAXIMUM_DISTANCE_FROM_ZERO:f64 = 1e-8;
self.x.abs() < MAXIMUM_DISTANCE_FROM_ZERO && self.x.abs() < MAXIMUM_DISTANCE_FROM_ZERO &&
@ -97,6 +84,21 @@ impl Vec3 {
let out_parallel = r * (*normal); let out_parallel = r * (*normal);
out_perp + out_parallel out_perp + out_parallel
} }
pub fn refract_sort_of_works(&self, normal: &Vec3, etai_over_etat: f64) -> Vec3 {
let dot = (-(*self)).dot(normal);
let cos_theta = dot.min(1.0);
let out_perp = etai_over_etat * ((*self) + cos_theta * (*normal));
let inner = 1.0 - out_perp.length_squared();
let abs = inner.abs();
let r = -(abs.sqrt());
let out_parallel = r * (*normal);
// Why?
let mut res = out_perp + out_parallel;
res.x = -res.x;
//res.y = -res.y;
res.z = -res.z;
res
}
} }
#[test] #[test]