Different materials
This commit is contained in:
parent
4156756a4f
commit
15d3a50d16
5 changed files with 153 additions and 28 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
|||
/target
|
||||
*.ppm
|
||||
*.jpg
|
||||
*.png
|
||||
flamegraph.svg
|
||||
perf.data*
|
||||
perf.data*
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
use super::Point3;
|
||||
use super::Ray;
|
||||
use super::Vec3;
|
||||
use super::{
|
||||
Point3,
|
||||
Vec3,
|
||||
Color,
|
||||
Ray,
|
||||
Material,
|
||||
Arc,
|
||||
Metal
|
||||
};
|
||||
|
||||
pub struct HitRecord {
|
||||
pub p: Point3,
|
||||
pub normal: Vec3,
|
||||
pub mat_ptr: Arc<dyn Material>,
|
||||
pub t: f64,
|
||||
front_face: bool,
|
||||
pub front_face: bool,
|
||||
}
|
||||
|
||||
pub struct Sphere {
|
||||
center: Point3,
|
||||
radius: f64,
|
||||
pub mat_ptr: Arc<dyn Material>,
|
||||
}
|
||||
|
||||
pub trait Hittable: Sync + Send {
|
||||
|
@ -28,10 +36,11 @@ impl HitRecord {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(p: Point3, normal: Vec3, t: f64, front_face: bool) -> Self {
|
||||
pub fn new(p: Point3, normal: Vec3, m: Arc<dyn Material>, t: f64, front_face: bool) -> Self {
|
||||
HitRecord {
|
||||
p: p,
|
||||
normal: normal,
|
||||
mat_ptr: m,
|
||||
t: t,
|
||||
front_face: front_face,
|
||||
}
|
||||
|
@ -39,8 +48,9 @@ impl HitRecord {
|
|||
|
||||
pub fn empty() -> Self {
|
||||
Self::new(
|
||||
Point3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Point3::null(),
|
||||
Vec3::null(),
|
||||
Arc::new(Metal::new(&Color::null())),
|
||||
0.0,
|
||||
false,
|
||||
)
|
||||
|
@ -48,10 +58,11 @@ impl HitRecord {
|
|||
}
|
||||
|
||||
impl Sphere {
|
||||
pub fn new(cen: Point3, r: f64) -> Self {
|
||||
pub fn new(cen: Point3, r: f64, m: Arc<dyn Material>) -> Self {
|
||||
Sphere {
|
||||
center: cen,
|
||||
radius: r,
|
||||
mat_ptr: m,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,12 +81,12 @@ impl Hittable for Sphere {
|
|||
|
||||
let sqrtd = discriminant.sqrt();
|
||||
|
||||
let root = (-half_b - sqrtd) / a;
|
||||
let mut root = (-half_b - sqrtd) / a;
|
||||
let normal = (r.at(root) - self.center) / self.radius;
|
||||
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
|
||||
let root2 = (-half_b + sqrtd) / a;
|
||||
let normal = (r.at(root2) - self.center) / self.radius;
|
||||
if root2 < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
|
||||
root = (-half_b + sqrtd) / a;
|
||||
let normal = (r.at(root) - self.center) / self.radius;
|
||||
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +95,7 @@ impl Hittable for Sphere {
|
|||
rec.p = r.at(rec.t);
|
||||
let outward_normal = (rec.p - self.center) / self.radius;
|
||||
rec.set_face_normal(r, outward_normal);
|
||||
rec.mat_ptr = self.mat_ptr.clone();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
53
src/main.rs
53
src/main.rs
|
@ -7,6 +7,7 @@ mod hittable_list;
|
|||
mod ray;
|
||||
mod utility;
|
||||
mod vec3;
|
||||
mod material;
|
||||
|
||||
use camera::Camera;
|
||||
use hittable::{HitRecord, Hittable, Sphere};
|
||||
|
@ -18,17 +19,25 @@ use std::env;
|
|||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use vec3::{Color, Point3, Vec3};
|
||||
use material::{Material, Lambertian, Metal};
|
||||
|
||||
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
|
||||
let mut rec = HitRecord::empty();
|
||||
|
||||
if depth <= 0 {
|
||||
return Color::new(0.0, 0.0, 0.0);
|
||||
return Color::null();
|
||||
}
|
||||
|
||||
if world.hit(r, 0.0, f64::INFINITY, &mut rec) {
|
||||
let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
|
||||
return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
|
||||
if world.hit(r, 0.001, f64::INFINITY, &mut rec) {
|
||||
let mut scattered = Ray::new(Point3::null(), Vec3::null());
|
||||
let mut attenuation = Color::null();
|
||||
if rec.mat_ptr.scatter(r, &rec, &mut attenuation, &mut scattered) {
|
||||
return attenuation * ray_color(&scattered, world, depth-1);
|
||||
}
|
||||
return Color::null();
|
||||
|
||||
//let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
|
||||
//return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
|
||||
}
|
||||
let unit_direction = r.direction();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
|
@ -41,32 +50,46 @@ fn main() {
|
|||
|
||||
// Image
|
||||
let aspect_ratio = 16.0 / 9.0;
|
||||
let image_width = 1000;
|
||||
let image_width = 1920;
|
||||
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
||||
let samples_per_pixel = 100_u32;
|
||||
let max_depth = 50;
|
||||
|
||||
// World
|
||||
let mut world = HittableList::new();
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(0.0, 0.0, -1.0),
|
||||
0.5,
|
||||
)));
|
||||
|
||||
let material_ground = Arc::new(Lambertian::new(&Color::new(0.8, 0.8, 0.0)));
|
||||
let material_center = Arc::new(Lambertian::new(&Color::new(0.7, 0.1, 0.2)));
|
||||
let material_left = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8)));
|
||||
let material_right = Arc::new(Metal::new(&Color::new(0.8, 0.6, 0.2)));
|
||||
let material_mirror = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.9)));
|
||||
|
||||
|
||||
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(0.0, -100.5, -1.0),
|
||||
100.0,
|
||||
material_ground.clone(),
|
||||
)));
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(1.0, 0.0, -1.5),
|
||||
0.3,
|
||||
Point3::new(0.0, 0.0, -1.0),
|
||||
0.5,
|
||||
material_center.clone(),
|
||||
)));
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(1.0, 1.1, -1.5),
|
||||
0.3,
|
||||
Point3::new(-1.0, 0.0, -1.0),
|
||||
0.5,
|
||||
material_mirror.clone(),
|
||||
)));
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(-1.0, 1.1, -1.5),
|
||||
0.3,
|
||||
Point3::new(1.0, 0.0, -1.0),
|
||||
0.5,
|
||||
material_mirror.clone(),
|
||||
)));
|
||||
world.add(Box::<Sphere>::new(Sphere::new(
|
||||
Point3::new(-1.0, 1.1, -1.2),
|
||||
0.4,
|
||||
material_left.clone(),
|
||||
)));
|
||||
|
||||
/*
|
||||
|
|
63
src/material.rs
Normal file
63
src/material.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
use super::{
|
||||
Ray,
|
||||
HitRecord,
|
||||
Color,
|
||||
Vec3,
|
||||
};
|
||||
|
||||
pub struct Lambertian {
|
||||
albedo: Color,
|
||||
}
|
||||
|
||||
pub struct Metal {
|
||||
albedo: Color,
|
||||
}
|
||||
|
||||
pub trait Material: Sync + Send {
|
||||
fn scatter(&self,r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
|
||||
}
|
||||
|
||||
impl Lambertian {
|
||||
pub fn new(a: &Color) -> Self {
|
||||
Lambertian {
|
||||
albedo: a.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Material for Lambertian {
|
||||
fn scatter(&self, _r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
||||
let mut scatter_direction = rec.normal + Vec3::random_unit_vector();
|
||||
|
||||
if scatter_direction.near_zero() {
|
||||
scatter_direction = rec.normal;
|
||||
}
|
||||
|
||||
*scattered = Ray::new(rec.p, scatter_direction);
|
||||
*attenuation = self.albedo.clone();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Metal {
|
||||
pub fn new(a: &Color) -> Self {
|
||||
Metal {
|
||||
albedo: *a,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> Self {
|
||||
Self::new(&self.albedo.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Material for Metal {
|
||||
fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
||||
let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal);
|
||||
|
||||
*scattered = Ray::new(rec.p, reflected);
|
||||
*attenuation = self.albedo.clone();
|
||||
|
||||
return Vec3::dot(scattered.direction(), rec.normal) > 0.0;
|
||||
}
|
||||
}
|
25
src/vec3.rs
25
src/vec3.rs
|
@ -14,6 +14,14 @@ impl Vec3 {
|
|||
Vec3 { e: [x, y, z] }
|
||||
}
|
||||
|
||||
pub fn null() -> Self {
|
||||
Self::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> Self {
|
||||
Self::new(self.x(), self.y(), self.z())
|
||||
}
|
||||
|
||||
pub fn length(&self) -> f64 {
|
||||
self.length_squared().sqrt()
|
||||
}
|
||||
|
@ -38,6 +46,15 @@ impl Vec3 {
|
|||
a / a.length()
|
||||
}
|
||||
|
||||
pub fn reflect(v: &Self, n: &Self) -> Self {
|
||||
*v - 2.0*Self::dot(*v, *n) * *(n)
|
||||
}
|
||||
|
||||
pub fn near_zero(&self) -> bool {
|
||||
let s = 1e-8;
|
||||
return (self.e[0].abs() < s) && (self.e[1].abs() < s) && (self.e[2].abs() < s);
|
||||
}
|
||||
|
||||
pub fn random_f64() -> Vec3 {
|
||||
Vec3::new(
|
||||
utility::random_f64(),
|
||||
|
@ -128,6 +145,14 @@ impl Mul<Vec3> for f64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul<Self> for Vec3 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self {
|
||||
Self::new(self.x()*rhs.x(), self.y()*rhs.y(), self.z()*rhs.z())
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f64> for Vec3 {
|
||||
fn mul_assign(&mut self, rhs: f64) {
|
||||
self.e[0] *= rhs;
|
||||
|
|
Loading…
Reference in a new issue