#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vec3 {
pub const fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
pub const ZERO: Vec3 = Vec3::new(0.0, 0.0, 0.0);
pub const X: Vec3 = Vec3::new(1.0, 0.0, 0.0);
pub const Y: Vec3 = Vec3::new(0.0, 1.0, 0.0);
pub const Z: Vec3 = Vec3::new(0.0, 0.0, 1.0);
pub fn add(self, o: Vec3) -> Vec3 {
Vec3::new(self.x + o.x, self.y + o.y, self.z + o.z)
}
pub fn sub(self, o: Vec3) -> Vec3 {
Vec3::new(self.x - o.x, self.y - o.y, self.z - o.z)
}
pub fn scale(self, s: f32) -> Vec3 {
Vec3::new(self.x * s, self.y * s, self.z * s)
}
pub fn dot(self, o: Vec3) -> f32 {
self.x * o.x + self.y * o.y + self.z * o.z
}
pub fn cross(self, o: Vec3) -> Vec3 {
Vec3::new(
self.y * o.z - self.z * o.y,
self.z * o.x - self.x * o.z,
self.x * o.y - self.y * o.x,
)
}
pub fn length(self) -> f32 {
self.dot(self).sqrt()
}
pub fn normalized(self) -> Vec3 {
let l = self.length();
if l < 1e-9 {
Vec3::ZERO
} else {
self.scale(1.0 / l)
}
}
pub fn lerp(self, o: Vec3, t: f32) -> Vec3 {
self.add(o.sub(self).scale(t))
}
pub fn any_perp(self) -> Vec3 {
let a = if self.x.abs() < 0.9 { Vec3::X } else { Vec3::Y };
self.cross(a).normalized()
}
}
impl From<Vec3> for [f32; 3] {
fn from(v: Vec3) -> [f32; 3] {
[v.x, v.y, v.z]
}
}
impl From<[f32; 3]> for Vec3 {
fn from(a: [f32; 3]) -> Vec3 {
Vec3::new(a[0], a[1], a[2])
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ray {
pub origin: Vec3,
pub dir: Vec3,
}
impl Ray {
pub fn at(&self, t: f32) -> Vec3 {
self.origin.add(self.dir.scale(t))
}
pub fn distance_to_point(&self, p: Vec3) -> f32 {
let w = p.sub(self.origin);
let t = w.dot(self.dir).max(0.0);
p.sub(self.at(t)).length()
}
pub fn distance_to_segment(&self, a: Vec3, b: Vec3) -> f32 {
let d1 = self.dir;
let d2 = b.sub(a);
let r = self.origin.sub(a);
let aa = d1.dot(d1);
let bb = d1.dot(d2);
let cc = d2.dot(d2);
let dd = d1.dot(r);
let ee = d2.dot(r);
let denom = aa * cc - bb * bb;
let (mut s, mut t) = if denom.abs() < 1e-9 {
(0.0, (ee / cc).clamp(0.0, 1.0))
} else {
let s = ((bb * ee - cc * dd) / denom).max(0.0);
let t = ((aa * ee - bb * dd) / denom).clamp(0.0, 1.0);
(s, t)
};
s = ((d1.dot(a.add(d2.scale(t)).sub(self.origin))) / aa).max(0.0);
let _ = &mut t;
let pr = self.at(s);
let ps = a.add(d2.scale(t));
pr.sub(ps).length()
}
pub fn intersect_plane(&self, p0: Vec3, n: Vec3) -> Option<f32> {
let denom = self.dir.dot(n);
if denom.abs() < 1e-9 {
return None;
}
Some(p0.sub(self.origin).dot(n) / denom)
}
}