122 lines
3 KiB
Rust
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 }
|
|
}
|