Implement motion blur

master
Max Nuding 2022-07-03 20:29:06 +02:00
parent 558851b5f6
commit 3de572d4a9
Signed by: phlaym
GPG Key ID: 0AAD39863E09DC48
5 changed files with 133 additions and 18 deletions

View File

@ -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
}
}
}

View File

@ -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
})
}
}

View File

@ -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();

View File

@ -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))
}
}

View File

@ -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();