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(a: T, b: T) -> T { if a < b { a } else { b } } #[inline] pub fn max(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 } }