Files
raytracing/src/objects/circle.rs
2026-05-12 18:20:06 +02:00

72 lines
1.6 KiB
Rust

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<dyn Material>,
}
impl Circle {
pub fn new(radius: f32, center: Vec3, normal: Vec3, material: Arc<dyn Material>) -> Self {
Self {
radius,
center,
normal: normal.get_unit(),
material,
}
}
}
impl Hittable for Circle {
fn hit(&self, r: &Ray) -> Option<Hit> {
// 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,
);
}
}