Implement dielectrics (glassy) materials.
Add Neg to Vec3.
This commit is contained in:
parent
7c213e3a2b
commit
b342e00d4c
@ -6,6 +6,7 @@ use rand::Rng;
|
|||||||
use rtiow::camera::Camera;
|
use rtiow::camera::Camera;
|
||||||
use rtiow::hitable::Hit;
|
use rtiow::hitable::Hit;
|
||||||
use rtiow::hitable_list::HitableList;
|
use rtiow::hitable_list::HitableList;
|
||||||
|
use rtiow::material::Dielectric;
|
||||||
use rtiow::material::Lambertian;
|
use rtiow::material::Lambertian;
|
||||||
use rtiow::material::Metal;
|
use rtiow::material::Metal;
|
||||||
use rtiow::ray::Ray;
|
use rtiow::ray::Ray;
|
||||||
@ -38,7 +39,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
Sphere::new(
|
Sphere::new(
|
||||||
Vec3::new(0., 0., -1.),
|
Vec3::new(0., 0., -1.),
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(Lambertian::new(Vec3::new(0.8, 0.3, 0.3))),
|
Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))),
|
||||||
),
|
),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
Vec3::new(0., -100.5, -1.),
|
Vec3::new(0., -100.5, -1.),
|
||||||
@ -50,10 +51,11 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
0.5,
|
0.5,
|
||||||
Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)),
|
Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)),
|
||||||
),
|
),
|
||||||
|
Sphere::new(Vec3::new(-1., 0., -1.), 0.5, Box::new(Dielectric::new(1.5))),
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
Vec3::new(-1., 0., -1.),
|
Vec3::new(-1., 0., -1.),
|
||||||
0.5,
|
-0.45,
|
||||||
Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.8)),
|
Box::new(Dielectric::new(1.5)),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
let cam = Camera::new2x1();
|
let cam = Camera::new2x1();
|
||||||
|
|||||||
83
rtiow/src/bin/tracer_dielectric.rs
Normal file
83
rtiow/src/bin/tracer_dielectric.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
extern crate rand;
|
||||||
|
extern crate rtiow;
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use rtiow::camera::Camera;
|
||||||
|
use rtiow::hitable::Hit;
|
||||||
|
use rtiow::hitable_list::HitableList;
|
||||||
|
use rtiow::material::Dielectric;
|
||||||
|
use rtiow::material::Lambertian;
|
||||||
|
use rtiow::material::Metal;
|
||||||
|
use rtiow::ray::Ray;
|
||||||
|
use rtiow::sphere::Sphere;
|
||||||
|
use rtiow::vec3::Vec3;
|
||||||
|
|
||||||
|
fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 {
|
||||||
|
if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) {
|
||||||
|
let scatter_response = rec.material.scatter(&r, &rec);
|
||||||
|
if depth < 50 && scatter_response.reflected {
|
||||||
|
return scatter_response.attenutation
|
||||||
|
* color(scatter_response.scattered, world, depth + 1);
|
||||||
|
}
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No hit, choose color from background.
|
||||||
|
let unit_direction = r.direction().unit_vector();
|
||||||
|
let t = 0.5 * (unit_direction.y + 1.);
|
||||||
|
Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let nx = 200;
|
||||||
|
let ny = 100;
|
||||||
|
let ns = 100;
|
||||||
|
println!("P3\n{} {}\n255", nx, ny);
|
||||||
|
let objects = vec![
|
||||||
|
Sphere::new(
|
||||||
|
Vec3::new(0., 0., -1.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))),
|
||||||
|
),
|
||||||
|
Sphere::new(
|
||||||
|
Vec3::new(0., -100.5, -1.),
|
||||||
|
100.,
|
||||||
|
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.))),
|
||||||
|
),
|
||||||
|
Sphere::new(
|
||||||
|
Vec3::new(1., 0., -1.),
|
||||||
|
0.5,
|
||||||
|
Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)),
|
||||||
|
),
|
||||||
|
Sphere::new(Vec3::new(-1., 0., -1.), 0.5, Box::new(Dielectric::new(1.5))),
|
||||||
|
Sphere::new(
|
||||||
|
Vec3::new(-1., 0., -1.),
|
||||||
|
-0.45,
|
||||||
|
Box::new(Dielectric::new(1.5)),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
let cam = Camera::new2x1();
|
||||||
|
let world = HitableList::new(objects.iter().map(|o| o).collect());
|
||||||
|
for j in (0..ny).rev() {
|
||||||
|
for i in 0..nx {
|
||||||
|
let mut col: Vec3 = Default::default();
|
||||||
|
for _ in 0..ns {
|
||||||
|
let u = (rng.gen_range::<f32>(0., 1.) + i as f32) / nx as f32;
|
||||||
|
let v = (rng.gen_range::<f32>(0., 1.) + j as f32) / ny as f32;
|
||||||
|
let r = cam.get_ray(u, v);
|
||||||
|
col = col + color(r, &world, 0);
|
||||||
|
}
|
||||||
|
col = col / ns as f32;
|
||||||
|
// Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2
|
||||||
|
// or sqrt.
|
||||||
|
col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt());
|
||||||
|
let ir = (255.99 * col[0]) as u32;
|
||||||
|
let ig = (255.99 * col[1]) as u32;
|
||||||
|
let ib = (255.99 * col[2]) as u32;
|
||||||
|
println!("{} {} {}", ir, ig, ib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@ -21,6 +21,7 @@ fn random_in_unit_sphere() -> Vec3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct ScatterResponse {
|
pub struct ScatterResponse {
|
||||||
pub scattered: Ray,
|
pub scattered: Ray,
|
||||||
pub attenutation: Vec3,
|
pub attenutation: Vec3,
|
||||||
@ -79,3 +80,65 @@ impl Material for Metal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refract(v: Vec3, n: Vec3, ni_over_nt: f32) -> Option<Vec3> {
|
||||||
|
let uv = v.unit_vector();
|
||||||
|
let dt = dot(uv, n);
|
||||||
|
let discriminant = 1. - ni_over_nt * ni_over_nt * (1. - dt * dt);
|
||||||
|
if discriminant > 0. {
|
||||||
|
return Some(ni_over_nt * (uv - n * dt) - n * discriminant.sqrt());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schlick(cosine: f32, ref_idx: f32) -> f32 {
|
||||||
|
let mut r0 = (1. - ref_idx) / (1. + ref_idx);
|
||||||
|
r0 = r0 * r0;
|
||||||
|
r0 + (1. - r0) * (1. - cosine).powf(5.)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dielectric {
|
||||||
|
ref_idx: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dielectric {
|
||||||
|
pub fn new(ref_idx: f32) -> Dielectric {
|
||||||
|
Dielectric { ref_idx }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material for Dielectric {
|
||||||
|
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
|
||||||
|
let reflected = reflect(r_in.direction(), rec.normal);
|
||||||
|
let (outward_normal, ni_over_nt, cosine) = if dot(r_in.direction(), rec.normal) > 0. {
|
||||||
|
(
|
||||||
|
-rec.normal,
|
||||||
|
self.ref_idx,
|
||||||
|
self.ref_idx * dot(r_in.direction(), rec.normal) / r_in.direction().length(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
rec.normal,
|
||||||
|
1. / self.ref_idx,
|
||||||
|
-dot(r_in.direction(), rec.normal) / r_in.direction().length(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let scattered =
|
||||||
|
if let Some(refracted) = refract(r_in.direction(), outward_normal, ni_over_nt) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
if rng.gen_range::<f32>(0., 1.) < schlick(cosine, self.ref_idx) {
|
||||||
|
Ray::new(rec.p, reflected)
|
||||||
|
} else {
|
||||||
|
Ray::new(rec.p, refracted)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ray::new(rec.p, reflected)
|
||||||
|
};
|
||||||
|
|
||||||
|
ScatterResponse {
|
||||||
|
attenutation: Vec3::new(1., 1., 1.),
|
||||||
|
scattered,
|
||||||
|
reflected: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use std::ops::Add;
|
|||||||
use std::ops::Div;
|
use std::ops::Div;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
|
use std::ops::Neg;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
@ -150,6 +151,14 @@ impl Mul<f32> for Vec3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec3 {
|
||||||
|
type Output = Vec3;
|
||||||
|
|
||||||
|
fn neg(self) -> Vec3 {
|
||||||
|
-1. * self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Sub for Vec3 {
|
impl Sub for Vec3 {
|
||||||
type Output = Vec3;
|
type Output = Vec3;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user