Files
raytracing/src/objects/sphere.rs
2026-05-03 14:58:56 +02:00

72 lines
1.7 KiB
Rust

use core::f32::math::sqrt;
use std::fmt::{self, Debug};
use std::sync::Arc;
use crate::Vec3;
use crate::objects::hit::Hit;
use crate::objects::materials::traits::Material;
use crate::objects::traits::Hittable;
use crate::ray::Ray;
pub struct Sphere {
center: Vec3,
radius: f32,
material: Arc<dyn Material>,
}
impl Debug for Sphere {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sphere")
.field("center", &self.center)
.field("radius", &self.radius)
.field("material", &self.material)
.finish()
}
}
impl Sphere {
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
Self {
center,
radius: r,
material: mat,
}
}
pub fn xyz(x: f32, y: f32, z: f32, r: f32, mat: Arc<dyn Material>) -> Self {
Self {
center: Vec3::new(x, y, z),
radius: r,
material: mat,
}
}
}
impl Hittable for Sphere {
fn hit(&self, r: &Ray) -> Option<Hit> {
let oc = self.center - r.origin();
let a = r.dir().length_squared();
let h = r.dir().dot(&oc);
let c = oc.length_squared() - self.radius * self.radius;
let d = h * h - a * c;
if d < 0. {
None
} else {
let tl = (h - sqrt(d)) / a;
let tr = (h + sqrt(d)) / a;
let t = if tl > 0.001 { tl } else { tr };
let p = r.at(t);
let out_n = (p - self.center) / self.radius;
Some(Hit::new(
t,
p,
(p - self.center).get_unit(),
self.material.clone(),
out_n.dot(r.dir()) < 0.,
))
}
}
}