72 lines
1.6 KiB
Rust
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,
|
|
);
|
|
}
|
|
}
|