61 lines
1.8 KiB
Rust
61 lines
1.8 KiB
Rust
use crate::hittable;
|
|
use crate::material::{Lambertian, Material, MaterialKind, Metal};
|
|
use crate::types_defined::{Color, HitRecord, Point, Ray, Sphere};
|
|
|
|
impl Sphere {
|
|
pub fn new(c: Point, r: f32, m: Option<MaterialKind>) -> Self {
|
|
Self {
|
|
center: c,
|
|
radius: r,
|
|
material: m,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl hittable::Hittable for Sphere {
|
|
fn hit(&self, r: &Ray, t_min: f32, t_max: f32, hit_record: &mut HitRecord) -> bool {
|
|
let a: f32 = r.direction.length_squared();
|
|
let h = r.direction.dot(self.center - r.point);
|
|
// let b = -2.0 * r.direction.dot(sphere_center - r.point);
|
|
let c = (self.center - r.point).length_squared() - self.radius * self.radius;
|
|
|
|
let discriminant = h * h - a * c;
|
|
|
|
if discriminant < 0.0 {
|
|
return false;
|
|
}
|
|
|
|
// // 两个交点
|
|
let disc_sqrt = discriminant.sqrt();
|
|
let near = (h - disc_sqrt) / a;
|
|
let far = (h + disc_sqrt) / a;
|
|
|
|
let mut root = near;
|
|
if root <= t_min || root >= t_max {
|
|
root = far;
|
|
if root <= t_min || root >= t_max {
|
|
hit_record.t = -1.0;
|
|
return false
|
|
}
|
|
}
|
|
|
|
let p = r.at(root);
|
|
let normal = (p - self.center) / self.radius;
|
|
|
|
hit_record.t = root;
|
|
hit_record.p = p;
|
|
hit_record.normal = normal;
|
|
hit_record.front_face = r.direction.dot(normal) < 0.0;
|
|
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())),
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
true
|
|
}
|
|
}
|
|
|