Implement motion blur
This commit is contained in:
parent
558851b5f6
commit
3de572d4a9
@ -1,3 +1,5 @@
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{Point3, Ray, Vec3};
|
||||
|
||||
pub struct Camera {
|
||||
@ -11,18 +13,22 @@ pub struct Camera {
|
||||
lens_radius: f64,
|
||||
u: Vec3,
|
||||
v: Vec3,
|
||||
w: Vec3
|
||||
w: Vec3,
|
||||
time0: f64,
|
||||
time1: f64
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
pub fn get_ray(&self, s: f64, t: f64) -> Ray {
|
||||
let rd = self.lens_radius * Vec3::random_unit_disk();
|
||||
let offset = self.u * rd.x() + self.v * rd.y();
|
||||
let time = rand::thread_rng().gen_range(self.time0..self.time1);
|
||||
Ray::new(
|
||||
self.origin + offset,
|
||||
self.lower_left_corner + s*self.horizontal + t*self.vertical - self.origin - offset)
|
||||
self.lower_left_corner + s*self.horizontal + t*self.vertical - self.origin - offset,
|
||||
time)
|
||||
}
|
||||
pub fn new(
|
||||
pub fn still(
|
||||
look_from: Point3,
|
||||
look_at: Point3,
|
||||
up: Vec3,
|
||||
@ -31,6 +37,29 @@ impl Camera {
|
||||
aperture: f64,
|
||||
focus_dist: f64) -> Self {
|
||||
|
||||
Camera::new(
|
||||
look_from,
|
||||
look_at,
|
||||
up,
|
||||
aspect_ratio,
|
||||
vfov,
|
||||
aperture,
|
||||
focus_dist,
|
||||
0.0,
|
||||
0.0)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
look_from: Point3,
|
||||
look_at: Point3,
|
||||
up: Vec3,
|
||||
aspect_ratio: f64,
|
||||
vfov: f64,
|
||||
aperture: f64,
|
||||
focus_dist: f64,
|
||||
time0: f64,
|
||||
time1: f64) -> Self {
|
||||
|
||||
let theta = vfov.to_radians();
|
||||
let h = (theta / 2.0).tan();
|
||||
let viewport_height = 2.0 * h;
|
||||
@ -53,7 +82,9 @@ impl Camera {
|
||||
lens_radius: aperture / 2.0,
|
||||
u,
|
||||
v,
|
||||
w
|
||||
w,
|
||||
time0,
|
||||
time1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,3 +62,68 @@ impl Hittable for Sphere {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MovableSphere {
|
||||
pub center0: Point3,
|
||||
pub center1: Point3,
|
||||
pub radius: f64,
|
||||
pub material: Material,
|
||||
pub time0: f64,
|
||||
pub time1: f64,
|
||||
}
|
||||
impl MovableSphere {
|
||||
pub fn new(
|
||||
center0: Point3,
|
||||
center1: Point3,
|
||||
radius: f64,
|
||||
material: Material,
|
||||
time0: f64,
|
||||
time1: f64) -> Self {
|
||||
MovableSphere { center0, center1, radius, material, time0, time1 }
|
||||
}
|
||||
pub fn center(&self, time: f64) -> Point3 {
|
||||
self.center0 + ((time - self.time0) / (self.time1 - self.time0))*(self.center1 - self.center0)
|
||||
}
|
||||
}
|
||||
impl Default for MovableSphere {
|
||||
fn default() -> Self {
|
||||
MovableSphere {
|
||||
center0: Point3::default(),
|
||||
center1: Point3::default(),
|
||||
radius: 0.0,
|
||||
material: Material::default(),
|
||||
time0: 0.0,
|
||||
time1: 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hittable for MovableSphere {
|
||||
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||
let oc = &ray.origin() - &self.center(ray.time());
|
||||
let a = ray.direction().length_squared();
|
||||
let half_b = oc.dot(&ray.direction());
|
||||
let c = oc.length_squared() - &self.radius * &self.radius;
|
||||
let discriminant = half_b * half_b - a * c;
|
||||
if discriminant < 0.0 { return None; }
|
||||
|
||||
let sqrtd = discriminant.sqrt();
|
||||
let mut root = (-half_b - sqrtd) / a;
|
||||
if root < t_min || t_max < root {
|
||||
root = (-half_b + sqrtd) / a;
|
||||
if root < t_min || t_max < root { return None; }
|
||||
}
|
||||
let point = ray.at(root);
|
||||
let normal = (point - self.center(ray.time())) / self.radius;
|
||||
let dot = ray.direction().dot(&normal);
|
||||
let front_face = dot < 0.0;
|
||||
let normal = if front_face { normal } else { -normal };
|
||||
Some(HitRecord {
|
||||
point,
|
||||
normal,
|
||||
t: root,
|
||||
front_face,
|
||||
material: &self.material
|
||||
})
|
||||
}
|
||||
}
|
29
src/main.rs
29
src/main.rs
@ -6,6 +6,8 @@ use crate::hittable::{Hittable, Sphere};
|
||||
use crate::output::{Output, P3, PNG};
|
||||
use crate::ray::Ray;
|
||||
use crate::vec3::{Color, Point3, Vec3};
|
||||
use hittable::MovableSphere;
|
||||
use rand::Rng;
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use crate::material::{Dielectric, Lambertian, Material, Metal};
|
||||
@ -50,11 +52,24 @@ fn random_scene() -> Vec<Box<dyn Hittable + Sync>> {
|
||||
fuzz_range.sample(&mut rng))),
|
||||
_ => Material::Dielectric(Dielectric::new(1.5)),
|
||||
};
|
||||
let sphere = Box::new(Sphere {
|
||||
center,
|
||||
radius: 0.2,
|
||||
material
|
||||
});
|
||||
let sphere: Box<dyn Hittable + Sync> = match rng.gen_bool(1.0 / 3.0) {
|
||||
true => {
|
||||
let center1 = center + Vec3::new(0.0, fuzz_range.sample(&mut rng) / 2.0, 0.0);
|
||||
Box::new(MovableSphere {
|
||||
center0: center,
|
||||
center1,
|
||||
radius: 0.2,
|
||||
material,
|
||||
time0: 0.0,
|
||||
time1: 1.0
|
||||
})
|
||||
}
|
||||
false => Box::new(Sphere {
|
||||
center,
|
||||
radius: 0.2,
|
||||
material
|
||||
})
|
||||
};
|
||||
world.push(sphere);
|
||||
}
|
||||
}
|
||||
@ -100,7 +115,9 @@ fn main() {
|
||||
ASPECT_RATIO,
|
||||
20.0,
|
||||
0.1,
|
||||
focus_dist);
|
||||
focus_dist,
|
||||
0.0,
|
||||
1.0);
|
||||
|
||||
// World
|
||||
let world= random_scene();
|
||||
|
@ -45,7 +45,7 @@ impl Scatterable for Lambertian {
|
||||
if direction.near_zero() {
|
||||
direction = hit_record.normal;
|
||||
}
|
||||
let scattered = Ray::new(hit_record.point, direction);
|
||||
let scattered = Ray::new(hit_record.point, direction, ray.time());
|
||||
Some((Some(scattered), self.albedo))
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ impl Scatterable for Metal {
|
||||
let reflected = ray.direction().unit_vector().reflected(&hit_record.normal);
|
||||
let scattered = Ray::new(
|
||||
hit_record.point,
|
||||
reflected + self.fuzz * Vec3::random_in_unit_sphere());
|
||||
reflected + self.fuzz * Vec3::random_in_unit_sphere(), ray.time());
|
||||
if scattered.direction().dot(&hit_record.normal) > 0.0 {
|
||||
Some((Some(scattered), self.albedo))
|
||||
} else {
|
||||
@ -113,11 +113,11 @@ impl Scatterable for Dielectric {
|
||||
|
||||
if cannot_refract || reflectance > rng.gen::<f64>() {
|
||||
let reflected = unit_direction.reflected(&hit_record.normal);
|
||||
let scattered = Ray::new(hit_record.point, reflected);
|
||||
let scattered = Ray::new(hit_record.point, reflected, ray.time());
|
||||
Some((Some(scattered), color))
|
||||
} else {
|
||||
let direction = unit_direction.refract(&hit_record.normal, refraction_ratio);
|
||||
let scattered = Ray::new(hit_record.point, direction);
|
||||
let scattered = Ray::new(hit_record.point, direction, ray.time());
|
||||
Some((Some(scattered), color))
|
||||
}
|
||||
}
|
||||
|
10
src/ray.rs
10
src/ray.rs
@ -6,23 +6,25 @@ use crate::vec3::Point3;
|
||||
#[derive(Debug)]
|
||||
pub struct Ray {
|
||||
origin: Point3,
|
||||
direction: Vec3
|
||||
direction: Vec3,
|
||||
time: f64
|
||||
}
|
||||
impl Default for Ray {
|
||||
fn default() -> Self {
|
||||
Ray::new(Vec3::default(), Vec3::default())
|
||||
Ray::new(Vec3::default(), Vec3::default(), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ray {
|
||||
pub fn new(origin: Point3, direction: Point3) -> Ray {
|
||||
Ray { origin, direction }
|
||||
pub fn new(origin: Point3, direction: Point3, time: f64) -> Ray {
|
||||
Ray { origin, direction, time }
|
||||
}
|
||||
pub fn at(&self, t: f64) -> Point3 {
|
||||
self.origin + self.direction * t
|
||||
}
|
||||
pub fn direction(&self) -> Vec3 { self.direction }
|
||||
pub fn origin(&self) -> Point3 { self.origin }
|
||||
pub fn time(&self) -> f64 { self.time }
|
||||
pub fn pixel_color(&self, world: &Vec<Box<dyn Hittable + Sync>>, depth: i32) -> Color {
|
||||
if depth <= 0 {
|
||||
return Color::default();
|
||||
|
Loading…
Reference in New Issue
Block a user