rtbvh 0.6.2

BVH library with various build algorithms and high performance using packet traversal.
Documentation
use glam::*;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(align(16))]
pub struct Ray {
    pub origin: Vec3,
    pub t_min: f32,
    pub direction: Vec3,
    pub t: f32,
    pub(crate) inv_direction: Vec3,
    pub(crate) signs: [u8; 4],
}

impl From<(Vec3, Vec3)> for Ray {
    fn from(vectors: (Vec3, Vec3)) -> Self {
        let signs = [
            (vectors.1.x < 0.0) as u8,
            (vectors.1.y < 0.0) as u8,
            (vectors.1.z < 0.0) as u8,
            0,
        ];

        Ray {
            origin: vectors.0,
            direction: vectors.1,
            inv_direction: Vec3::ONE / vectors.1,
            t_min: 1e-4,
            t: 1e34,
            signs,
        }
    }
}

impl From<Ray> for (Vec3, Vec3) {
    fn from(r: Ray) -> Self {
        (r.origin, r.direction)
    }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(align(16))]
#[derive(Debug, Copy, Clone)]
pub struct RayPacket4 {
    pub origin_x: Vec4,
    pub origin_y: Vec4,
    pub origin_z: Vec4,

    pub direction_x: Vec4,
    pub direction_y: Vec4,
    pub direction_z: Vec4,

    pub inv_direction_x: Vec4,
    pub inv_direction_y: Vec4,
    pub inv_direction_z: Vec4,

    pub t: Vec4,
}

impl RayPacket4 {
    pub fn new(origins: [Vec4; 4], directions: [Vec4; 4]) -> RayPacket4 {
        Self {
            origin_x: vec4(origins[0].x, origins[1].x, origins[2].x, origins[3].x),
            origin_y: vec4(origins[0].y, origins[1].y, origins[2].y, origins[3].y),
            origin_z: vec4(origins[0].z, origins[1].z, origins[2].z, origins[3].z),
            direction_x: vec4(
                directions[0].x,
                directions[1].x,
                directions[2].x,
                directions[3].x,
            ),
            direction_y: vec4(
                directions[0].y,
                directions[1].y,
                directions[2].y,
                directions[3].y,
            ),
            direction_z: vec4(
                directions[0].z,
                directions[1].z,
                directions[2].z,
                directions[3].z,
            ),
            inv_direction_x: vec4(
                1.0 / directions[0].x,
                1.0 / directions[1].x,
                1.0 / directions[2].x,
                1.0 / directions[3].x,
            ),
            inv_direction_y: vec4(
                1.0 / directions[0].y,
                1.0 / directions[1].y,
                1.0 / directions[2].y,
                1.0 / directions[3].y,
            ),
            inv_direction_z: vec4(
                1.0 / directions[0].z,
                1.0 / directions[1].z,
                1.0 / directions[2].z,
                1.0 / directions[3].z,
            ),
            t: Vec4::splat(1e34),
        }
    }

    pub fn origin_xyz(&self) -> (Vec4, Vec4, Vec4) {
        (self.origin_x, self.origin_y, self.origin_z)
    }

    pub fn direction_xyz(&self) -> (Vec4, Vec4, Vec4) {
        (self.direction_x, self.direction_y, self.direction_z)
    }

    #[inline]
    pub fn ray(&self, index: usize) -> Ray {
        debug_assert!(index <= 4);

        let origin = vec3(
            self.origin_x[index],
            self.origin_y[index],
            self.origin_z[index],
        );

        let direction = vec3(
            self.direction_x[index],
            self.direction_y[index],
            self.direction_z[index],
        );

        let signs = [
            (direction.x < 0.0) as u8,
            (direction.y < 0.0) as u8,
            (direction.z < 0.0) as u8,
            0,
        ];

        Ray {
            origin,
            t_min: 1e-4,
            direction,
            t: self.t[index],
            inv_direction: Vec3::ONE / direction,
            signs,
        }
    }

    #[inline(always)]
    pub fn t(&self) -> Vec4 {
        self.t
    }

    #[inline(always)]
    pub fn reset(&mut self) {
        self.t = Vec4::splat(Ray::DEFAULT_T_MAX);
    }
}

#[allow(dead_code)]
impl Ray {
    pub const DEFAULT_T_MIN: f32 = 1e-4;
    pub const DEFAULT_T_MAX: f32 = 1e34;

    pub fn new(origin: Vec3, direction: Vec3) -> Ray {
        let signs = [
            (direction.x < 0.0) as u8,
            (direction.y < 0.0) as u8,
            (direction.z < 0.0) as u8,
            0,
        ];

        Ray {
            origin,
            direction,
            t_min: Self::DEFAULT_T_MIN,
            t: Self::DEFAULT_T_MAX,
            inv_direction: Vec3::ONE / direction,
            signs,
        }
    }

    #[inline]
    pub fn reflect(&self, hit_point: Vec3, n: Vec3, epsilon: f32) -> Ray {
        let tmp: Vec3 = n * n.dot(self.direction) * 2.0;
        let direction = self.direction - tmp;

        let signs = [
            (direction.x < 0.0) as u8,
            (direction.y < 0.0) as u8,
            (direction.z < 0.0) as u8,
            0,
        ];

        Ray {
            origin: hit_point + direction * epsilon,
            direction,
            inv_direction: Vec3::ONE / direction,
            t_min: Self::DEFAULT_T_MIN,
            t: Self::DEFAULT_T_MAX,
            signs,
        }
    }

    #[inline(always)]
    pub fn is_valid(&self) -> bool {
        self.t < 1e33
    }

    #[inline(always)]
    pub fn get_point_at(&self, t: f32) -> Vec3 {
        self.origin + t * self.direction
    }

    #[inline(always)]
    pub(crate) fn sign_x(&self) -> usize {
        self.signs[0] as usize
    }

    #[inline(always)]
    pub(crate) fn sign_y(&self) -> usize {
        self.signs[1] as usize
    }

    #[inline(always)]
    pub(crate) fn sign_z(&self) -> usize {
        self.signs[2] as usize
    }

    #[inline(always)]
    pub fn reset(&mut self) {
        self.t = Self::DEFAULT_T_MAX;
    }
}