Dielectric bug
This commit is contained in:
parent
b28a6cc7f5
commit
37c4cbb666
|
@ -2,7 +2,7 @@ use std::fs::File;
|
|||
use std::io::{BufWriter};
|
||||
|
||||
use crate::hittable::HittableList;
|
||||
use crate::math_utils::clamp;
|
||||
use crate::math_utils::{clamp, near_zero};
|
||||
use crate::ppm_writer::PPMWriter;
|
||||
use crate::types_defined::{Camera, Color, HitRecord, Point, Ray, Vec3};
|
||||
use rand::rngs::ThreadRng;
|
||||
|
@ -125,12 +125,12 @@ impl<'a> Camera<'a> {
|
|||
};
|
||||
let hit_c = match hit_m {
|
||||
Some(mk) => {
|
||||
let mc = match mk {
|
||||
match mk {
|
||||
// MaterialKind::Lambertian(l) => l.albedo,
|
||||
MaterialKind::Lambertian(l) => self.scatter_color(ray, hc, l, depth, world),
|
||||
MaterialKind::Metal(m) => self.scatter_color(ray, hc, m, depth, world),
|
||||
};
|
||||
mc
|
||||
MaterialKind::Dielectric(d) => self.scatter_color(ray, hc, d, depth, world)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if hit_record.t >= 0.0 {
|
||||
|
@ -175,7 +175,11 @@ impl<'a> Camera<'a> {
|
|||
attenuation.y * r_c.y,
|
||||
attenuation.z * r_c.z,
|
||||
);
|
||||
Color::new(sc_color.x, sc_color.y, sc_color.z)
|
||||
let color = Color::new(sc_color.x, sc_color.y, sc_color.z);
|
||||
// if near_zero(color) {
|
||||
// println!("near zero: {:?}", scatted.direction);
|
||||
// }
|
||||
color
|
||||
} else {
|
||||
Color::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::material::MaterialKind;
|
||||
use crate::math_utils::{front_face_normal, is_front_face};
|
||||
use crate::types_defined::{HitRecord, Ray, Vec3};
|
||||
|
||||
pub trait Hittable {
|
||||
|
@ -37,20 +38,17 @@ impl HittableList {
|
|||
closest_so_far = temp_hit_record.t;
|
||||
hit_record.t = temp_hit_record.t;
|
||||
hit_record.p = temp_hit_record.p;
|
||||
hit_record.front_face = temp_hit_record.front_face;
|
||||
hit_record.normal = temp_hit_record.normal;
|
||||
hit_record.front_face = is_front_face(r, temp_hit_record.normal);
|
||||
hit_record.normal = front_face_normal(r, temp_hit_record.normal);
|
||||
hit_record.material = if let Some(ref m) = temp_hit_record.material {
|
||||
match m {
|
||||
MaterialKind::Lambertian(l) => Some(MaterialKind::Lambertian(l.clone())),
|
||||
MaterialKind::Metal(m) => Some(MaterialKind::Metal(m.clone())),
|
||||
MaterialKind::Dielectric(d) => Some(MaterialKind::Dielectric(d.clone()))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// if temp_hit_record.t >= 0.0 {
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -2,7 +2,7 @@ use std::fs::File;
|
|||
use std::io::BufWriter;
|
||||
|
||||
use crate::hittable::HittableList;
|
||||
use crate::material::{Lambertian, MaterialKind, Metal};
|
||||
use crate::material::{Dielectric, Lambertian, MaterialKind, Metal};
|
||||
use crate::ppm_writer::PPMWriter;
|
||||
use crate::types_defined::{Camera, Color, Point, Sphere, Vec3};
|
||||
mod camera;
|
||||
|
@ -22,8 +22,13 @@ fn main() {
|
|||
|
||||
fn camera_render() {
|
||||
|
||||
let width: i32 = 800/2;
|
||||
let height: i32 = 600/2;
|
||||
let scale = 2;
|
||||
let width: i32 = 800/scale;
|
||||
let height: i32 = 600/scale;
|
||||
let sample_times = 50;
|
||||
let reflect_depth = 100;
|
||||
|
||||
|
||||
let pw_r = PPMWriter::new(
|
||||
BufWriter::new(File::create("./target/ray_sphere_normal_scene_render.ppm").unwrap()),
|
||||
width, height);
|
||||
|
@ -36,12 +41,12 @@ fn camera_render() {
|
|||
|
||||
let mut camera: Camera = Camera::new(
|
||||
width,
|
||||
4.0 / 3.0,
|
||||
width as f32 / height as f32,
|
||||
2.0,
|
||||
Point::new(0.0, -0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, 1.0),
|
||||
127,
|
||||
127,
|
||||
sample_times,
|
||||
reflect_depth,
|
||||
pw
|
||||
);
|
||||
// world
|
||||
|
@ -50,20 +55,18 @@ fn camera_render() {
|
|||
|
||||
let plane_m = Some(MaterialKind::Lambertian(Lambertian{albedo: Color::new(0.899, 0.899, 0.999)}));
|
||||
// let plane2_m = Some(MaterialKind::Metal(Metal{albedo: Color::new(0.784,0.784,0.784)}));
|
||||
let center_m = Some(MaterialKind::Lambertian(Lambertian{albedo: Color::new(0.5, 0.5, 0.5)}));
|
||||
let center_m = Some(MaterialKind::Lambertian(Lambertian{albedo: Color::new(0.2, 0.5, 0.5)}));
|
||||
let left_m = Some(MaterialKind::Metal(Metal{albedo: Color::new(0.799, 0.599, 0.799), fuzz: 0.0005}));
|
||||
let left_behind_m = Some(MaterialKind::Lambertian(Lambertian{albedo: Color::new(0.799, 0.599, 0.599)}));
|
||||
let right_m = Some(MaterialKind::Metal(Metal{albedo: Color::new(0.8, 0.6, 0.2), fuzz: 0.3}));
|
||||
let right_m = Some(MaterialKind::Metal(Metal{albedo: Color::new(0.8, 0.6, 0.2), fuzz: 0.003}));
|
||||
let left_dia_m = Some(MaterialKind::Dielectric(Dielectric{albedo: Color::new(0.8, 0.6, 0.2), refraction_index: 1.5}));
|
||||
|
||||
world.put(Box::new(Sphere::new(Point::new(0.0, 0.0, -1.0), 0.5, center_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(-1.0, 0.0, -1.0), 0.5, left_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(-2.5, 1.5, -3.5), 1.5, left_behind_m)));
|
||||
// world.put(Box::new(Sphere::new(Point::new(0.0, 0.0, -1.0), 0.5, center_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(-1.0, 0.0, -1.0), 0.5, left_dia_m)));
|
||||
// world.put(Box::new(Sphere::new(Point::new(-1.0, 0.0, -1.0), 0.5, left_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(-3.5, 1.5, -5.5), 1.5, left_behind_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(1.0, 0.0, -1.0), 0.5, right_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(0.0, -25.5, -1.0), 25.0, plane_m)));
|
||||
world.put(Box::new(Sphere::new(Point::new(0.0, -500.5, -1.0), 500.0, plane_m)));
|
||||
|
||||
camera.render(&world);
|
||||
// write_image(
|
||||
// ppm_content,
|
||||
// "".to_string(),
|
||||
// )
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::math_utils::{reflect};
|
||||
use crate::math_utils::{near_zero, reflect, refract};
|
||||
use crate::types_defined::{Color, HitRecord, Ray, Vec3};
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@ use crate::types_defined::{Color, HitRecord, Ray, Vec3};
|
|||
pub enum MaterialKind {
|
||||
Lambertian(Lambertian),
|
||||
Metal(Metal),
|
||||
Dielectric (Dielectric),
|
||||
}
|
||||
|
||||
pub trait Material {
|
||||
|
@ -28,13 +29,12 @@ impl Clone for Lambertian {
|
|||
impl Material for Lambertian {
|
||||
fn scatter(&self, r_in: &Ray, hit_record: &mut HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
||||
|
||||
let scatter_direction = r_in.direction + Vec3::random_unit_on_hemisphere(hit_record.normal);
|
||||
// hit_record.normal + Vec3::random_unit();
|
||||
// let scatter_direction = reflect(r_in.direction, hit_record.normal);
|
||||
let mut scatter_direction = r_in.direction + Vec3::random_unit_on_hemisphere(hit_record.normal);
|
||||
|
||||
// if near_zero(scatter_direction) {
|
||||
// scattered.direction = r_in.direction;
|
||||
// }
|
||||
if (near_zero(scatter_direction)) {
|
||||
scatter_direction = hit_record.normal;
|
||||
}
|
||||
|
||||
|
||||
*scattered = Ray::new(hit_record.p, scatter_direction);
|
||||
*attenuation = self.albedo.clone();
|
||||
|
@ -66,4 +66,63 @@ impl Material for Metal {
|
|||
*attenuation = self.albedo.clone();
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Dielectric {
|
||||
fn clone(&self) -> Self {
|
||||
Dielectric {
|
||||
albedo: self.albedo,
|
||||
refraction_index: self.refraction_index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dielectric {
|
||||
pub albedo: Color,
|
||||
pub refraction_index: f32
|
||||
}
|
||||
|
||||
impl Material for Dielectric {
|
||||
fn scatter(&self, r_in: &Ray, hit_record: &mut HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
|
||||
|
||||
// attenuation = color(1.0, 1.0, 1.0);
|
||||
// double ri = rec.front_face ? (1.0/refraction_index) : refraction_index;
|
||||
|
||||
// vec3 unit_direction = unit_vector(r_in.direction());
|
||||
// vec3 refracted = refract(unit_direction, rec.normal, ri);
|
||||
|
||||
// scattered = ray(rec.p, refracted);
|
||||
// return true;
|
||||
*attenuation = Color::new(1.0, 1.0, 1.0);
|
||||
let ri = if hit_record.front_face {
|
||||
1.0 / self.refraction_index
|
||||
} else {
|
||||
self.refraction_index
|
||||
};
|
||||
|
||||
let unit_direction = r_in.direction.normalize();
|
||||
let refracted = refract(unit_direction, hit_record.normal, ri);
|
||||
*scattered = Ray::new(hit_record.p, refracted);
|
||||
|
||||
true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// *attenuation = Color::new(1.0, 1.0, 1.0);
|
||||
// let ri = if hit_record.front_face {
|
||||
// 1.0/self.refraction_index
|
||||
// } else {
|
||||
// self.refraction_index
|
||||
// };
|
||||
|
||||
// let normalized = r_in.direction;
|
||||
// let refracted = refract(normalized, hit_record.normal, ri);
|
||||
// *scattered = Ray::new(hit_record.p, refracted);
|
||||
// true
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::types_defined::Vec3;
|
||||
use crate::types_defined::{Ray, Vec3};
|
||||
|
||||
pub fn clamp(value: f32, low: f32, high: f32) -> f32 {
|
||||
if value < low {
|
||||
|
@ -10,12 +10,55 @@ pub fn clamp(value: f32, low: f32, high: f32) -> f32 {
|
|||
return value;
|
||||
}
|
||||
|
||||
// pub fn near_zero(v: Vec3) -> bool {
|
||||
// const EPSILON: f32 = 1e-4;
|
||||
pub fn near_zero(v: Vec3) -> bool {
|
||||
const EPSILON: f32 = 1e-4;
|
||||
|
||||
// v.x.abs() < EPSILON && v.y.abs() < EPSILON && v.z.abs() < EPSILON
|
||||
// }
|
||||
v.x.abs() < EPSILON && v.y.abs() < EPSILON && v.z.abs() < EPSILON
|
||||
}
|
||||
|
||||
pub fn reflect(v: Vec3, n: Vec3) -> Vec3 {
|
||||
v - ((2.0 * v.dot(n)) * n)
|
||||
}
|
||||
|
||||
// v, normal, 折射率
|
||||
pub fn refract(uv: Vec3, n: Vec3, etai_over_etat: f32) -> Vec3 {
|
||||
// auto cos_theta = std::fmin(dot(-uv, n), 1.0);
|
||||
// vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n);
|
||||
// vec3 r_out_parallel = -std::sqrt(std::fabs(1.0 - r_out_perp.length_squared())) * n;
|
||||
// return r_out_perp + r_out_parallel;
|
||||
let cos_theta = (-uv.dot(n)).min(1.0);
|
||||
let r_out_perp = etai_over_etat * (uv + cos_theta * n);
|
||||
let r_out_parallel = -(f32::sqrt(f32::abs(1.0 - r_out_perp.length()))) * n;
|
||||
r_out_perp + r_out_parallel
|
||||
|
||||
// let v_normalized = v;
|
||||
// let n_normalized = n.normalize();
|
||||
|
||||
// let cos_theta = f32::min(-v_normalized.dot(n_normalized), 1.0);
|
||||
// let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();
|
||||
// // 检查是否全内反射(无法折射)
|
||||
// if etai_over_etat * sin_theta > 1.0 {
|
||||
// return reflect(v_normalized, n)
|
||||
// }
|
||||
|
||||
// let r_out_perp = etai_over_etat * (v_normalized + cos_theta * n_normalized);
|
||||
// let discriminant = 1.0 - r_out_perp.length_squared();
|
||||
// // if discriminant < 0.0 {
|
||||
// // return -1.0 * v; // 全内反射,返回零向量(或改为反射)
|
||||
// // }
|
||||
// let r_out_parallel = -discriminant * n_normalized;
|
||||
|
||||
// r_out_perp + r_out_parallel
|
||||
}
|
||||
|
||||
pub fn is_front_face(r: &Ray, outward_normal: Vec3) -> bool {
|
||||
r.direction.dot(outward_normal) < 0.0
|
||||
}
|
||||
|
||||
pub fn front_face_normal(r: &Ray, outward_normal: Vec3) -> Vec3 {
|
||||
if is_front_face(r, outward_normal) {
|
||||
outward_normal
|
||||
} else {
|
||||
-1. * outward_normal
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use crate::hittable;
|
||||
use crate::material::{MaterialKind};
|
||||
use crate::math_utils::{front_face_normal, is_front_face};
|
||||
use crate::types_defined::{HitRecord, Point, Ray, Sphere};
|
||||
|
||||
impl Sphere {
|
||||
|
@ -44,12 +45,13 @@ impl hittable::Hittable for Sphere {
|
|||
|
||||
hit_record.t = root;
|
||||
hit_record.p = p;
|
||||
hit_record.normal = normal;
|
||||
hit_record.front_face = r.direction.dot(normal) < 0.0;
|
||||
hit_record.normal = front_face_normal(r, normal);
|
||||
hit_record.front_face = is_front_face(r, normal);
|
||||
hit_record.material = if let Some(ref m) = self.material {
|
||||
match m {
|
||||
MaterialKind::Lambertian(l) => Some(MaterialKind::Lambertian(l.clone())),
|
||||
MaterialKind::Metal(m) => Some(MaterialKind::Metal(m.clone())),
|
||||
MaterialKind::Dielectric(d) => Some(MaterialKind::Dielectric(d.clone())),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -53,6 +53,7 @@ pub struct Camera<'a> {
|
|||
pub ppm_file_writer: &'a mut PPMWriter<BufWriter<File>>
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/////////////
|
||||
// for test
|
||||
|
@ -62,4 +63,4 @@ pub struct Sphere {
|
|||
pub center: Point,
|
||||
pub radius: f32,
|
||||
pub material: Option<MaterialKind>,
|
||||
}
|
||||
}
|
12
src/vec3.rs
12
src/vec3.rs
|
@ -37,6 +37,18 @@ impl Vec3 {
|
|||
return self.length_squared().sqrt();
|
||||
}
|
||||
|
||||
pub fn normalize(self) -> Vec3 {
|
||||
let length = self.length_squared().sqrt();
|
||||
if length != 0. {
|
||||
let new_x = self.x / length;
|
||||
let new_y = self.y / length;
|
||||
let new_z = self.z / length;
|
||||
Vec3 { x: new_x, y: new_y, z: new_z }
|
||||
} else {
|
||||
Vec3 { x: 0., y: 0., z: 0. }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_range(min: f32, max: f32) -> Self {
|
||||
let rng = &mut thread_rng();
|
||||
Vec3::new(rng.gen_range(min..max), rng.gen_range(min..max), rng.gen_range(min..max))
|
||||
|
|
Loading…
Reference in New Issue