//! Utilities for handling floating point precision issues //! //! This is based on the work in section 3.9 of "Physically Based Rendering: //! From Theory to Implementation" 3rd edition by Pharr et al. use crate::math::{dot, Normal, Point, Vector}; pub use rmath::utils::{decrement_ulp, increment_ulp}; #[inline(always)] pub fn fp_gamma(n: u32) -> f32 { use std::f32::EPSILON; let e = EPSILON * 0.5; (e * n as f32) / (1.0 - (e * n as f32)) } pub fn robust_ray_origin(pos: Point, pos_err: f32, nor: Normal, ray_dir: Vector) -> Point { // Get surface normal pointing in the same // direction as ray_dir. let nor = { let nor = nor.into_vector(); if dot(nor, ray_dir) >= 0.0 { nor } else { -nor } }; // Calculate offset point let d = dot(nor.abs(), Vector::new(pos_err, pos_err, pos_err)); let offset = nor * d; let p = pos + offset; // Calculate ulp offsets let x = if nor.x() >= 0.0 { increment_ulp(p.x()) } else { decrement_ulp(p.x()) }; let y = if nor.y() >= 0.0 { increment_ulp(p.y()) } else { decrement_ulp(p.y()) }; let z = if nor.z() >= 0.0 { increment_ulp(p.z()) } else { decrement_ulp(p.z()) }; Point::new(x, y, z) } // #[cfg(test)] // mod tests { // use super::*; // }