use std::{f32::consts::PI, sync::Arc}; use crate::{ objects::{materials::traits::Material, traits::Hittable}, ray::Ray, vec3::Vec3, }; use super::hit::Hit; #[derive(Debug)] pub struct Circle { radius: f32, center: Vec3, normal: Vec3, material: Arc, } impl Circle { pub fn new(radius: f32, center: Vec3, normal: Vec3, material: Arc) -> Self { Self { radius, center, normal: normal.get_unit(), material, } } } impl Hittable for Circle { fn hit(&self, r: &Ray) -> Option { // check if ray parallel to plane let dot = self.normal.dot(r.dir()); if dot == 0.0 { return None; } // hitpoint on plane let t = self.normal.dot(&(self.center - r.origin())) / dot; // hits behind camera if t < 0. { return None; }; let p = r.at(t); if (p - self.center).length() < self.radius { let uv = self.to_uv(&p); return Some(Hit::new( t, p, self.normal, self.material.clone(), self.normal.dot(&r.dir()) < 0., *uv.x(), *uv.y(), )); } None } fn to_uv(&self, point: &Vec3) -> Vec3 { let p = *point - self.center; // TODO: add rotated texture support return Vec3::new( 0.5 + p.y().atan2(*p.x()) / (2. * PI), 1. - (p.z() / self.radius).acos() / PI, 0.0, ); } }