pbrt/src/core/geometry/mod.rs
2025-12-11 17:28:06 +00:00

122 lines
3 KiB
Rust

pub mod bounds;
pub mod cone;
pub mod primitives;
pub mod ray;
pub mod traits;
pub use self::bounds::{Bounds, Bounds2f, Bounds2fi, Bounds2i, Bounds3f, Bounds3fi, Bounds3i};
pub use self::cone::DirectionCone;
pub use self::primitives::{
Frame, Normal, Normal3f, Point, Point2f, Point2fi, Point2i, Point3, Point3f, Point3fi, Point3i,
Vector, Vector2, Vector2f, Vector2fi, Vector2i, Vector3, Vector3f, Vector3fi, Vector3i,
};
pub use self::ray::{Ray, RayDifferential};
pub use self::traits::{Lerp, Sqrt, Tuple, VectorLike};
use crate::core::pbrt::{Float, PI, clamp_t};
use crate::utils::math::square;
use num_traits::Float as NumFloat;
#[inline]
pub fn min<T: PartialOrd>(a: T, b: T) -> T {
if a < b { a } else { b }
}
#[inline]
pub fn max<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
#[inline]
pub fn cos_theta(w: Vector3f) -> Float {
w.z()
}
#[inline]
pub fn abs_cos_theta(w: Vector3f) -> Float {
w.z().abs()
}
#[inline]
pub fn cos2_theta(w: Vector3f) -> Float {
square(w.z())
}
#[inline]
pub fn sin2_theta(w: Vector3f) -> Float {
0_f32.max(1. - cos2_theta(w))
}
#[inline]
pub fn sin_theta(w: Vector3f) -> Float {
sin2_theta(w).sqrt()
}
#[inline]
pub fn tan_theta(w: Vector3f) -> Float {
sin_theta(w) / cos_theta(w)
}
#[inline]
pub fn tan2_theta(w: Vector3f) -> Float {
sin2_theta(w) / cos2_theta(w)
}
#[inline]
pub fn cos_phi(w: Vector3f) -> Float {
let sin_theta = sin_theta(w);
if sin_theta == 0. {
1.
} else {
clamp_t(w.x() / sin_theta, -1., 1.)
}
}
#[inline]
pub fn sin_phi(w: Vector3f) -> Float {
let sin_theta = sin_theta(w);
if sin_theta == 0. {
0.
} else {
clamp_t(w.y() / sin_theta, -1., 1.)
}
}
pub fn same_hemisphere(w: Vector3f, wp: Vector3f) -> bool {
w.z() * wp.z() > 0.
}
pub fn spherical_direction(sin_theta: Float, cos_theta: Float, phi: Float) -> Vector3f {
Vector3f::new(sin_theta * phi.cos(), sin_theta * phi.sin(), cos_theta)
}
pub fn spherical_triangle_area(a: Vector3f, b: Vector3f, c: Vector3f) -> Float {
(2.0 * (a.dot(b.cross(c))).atan2(1.0 + a.dot(b) + a.dot(c) + b.dot(c))).abs()
}
pub fn spherical_quad_area(a: Vector3f, b: Vector3f, c: Vector3f, d: Vector3f) -> Float {
let mut axb = a.cross(b);
let mut bxc = b.cross(c);
let mut cxd = c.cross(d);
let mut dxa = d.cross(a);
if axb.norm_squared() == 0.
|| bxc.norm_squared() == 0.
|| cxd.norm_squared() == 0.
|| dxa.norm_squared() == 0.
{
return 0.;
}
axb = axb.normalize();
bxc = bxc.normalize();
cxd = cxd.normalize();
dxa = dxa.normalize();
let alpha = dxa.angle_between(-axb);
let beta = axb.angle_between(-bxc);
let gamma = bxc.angle_between(-cxd);
let delta = cxd.angle_between(-dxa);
(alpha + beta + gamma + delta - 2. * PI).abs()
}
pub fn spherical_theta(v: Vector3f) -> Float {
clamp_t(v.z(), -1.0, 1.0).acos()
}
pub fn spherical_phi(v: Vector3f) -> Float {
let p = v.y().atan2(v.x());
if p < 0.0 { p + 2.0 * PI } else { p }
}