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