#voxel #traversal #query #2d-3d #raycasting #raymarching #bounding-volume

fast-voxel-traversal

Fast voxel traversal iterators for both 2D and 3D

2 unstable releases

0.5.0 Sep 7, 2021
0.4.0 Sep 7, 2021

#10 in #bounding-volume

MIT license

18KB
390 lines

Fast Voxel Traversal

This crate provies iterators for traversing a ray through both 2D and 3D voxel volumes. It is based on this JS impl which is itself based on a this paper by Amanatides and Woo.

See the examples/ folder for usage.

use fast_voxel_traversal::raycast_3d::*;
use glam::{IVec3, Vec3};

fn main() {
    // Create a bounding volume. Volmes always start at (0, 0, 0) with a given size. This doesn't
    // actually allocate a volume, it just stores the size. If you need to query a voxel volume that
    // doesn't start a (0, 0, 0), simply subtract the offset from the ray's origin, then add the
    // offset back in during each traversal iteration.
    let volume = BoundingVolume3 {
        size: IVec3::ONE * 8,
    };

    // Create a ray that we will intersect with our voxels.
    let ray = Ray3 {
        origin: -Vec3::ONE * 10.0,
        direction: Vec3::ONE,
        length: 100.0,
    };

    // Traverse the ray through the volume.
    for hit in volume.traverse_ray(ray) {
        // The position of the voxel that was traversed. This will always be a voxel within the
        // bounding volume.
        let _position = hit.voxel;

        // The normal of the face that was 'entered' when the ray traversed the voxel. This can be
        // `None` for the first voxel if the ray started within a voxel.
        let _normal = hit.normal;

        // The distance from the ray origin this hit occured.
        let _distance = hit.distance;

        // The world space hit point is easy to compute from this, if you need it:
        let _world_space_hit_point = ray.origin + (ray.direction * hit.distance);

        println!("{:?}", hit);
    }

    let ray_doesnt_intersect = Ray3 {
        origin: -Vec3::ONE,
        direction: Vec3::X,
        length: f32::INFINITY,
    };

    // Casting an infinite ray, or one that never hits a volume won't infinite-loop (although it may
    // be slightly slower in such degerate cases).
    for _hit in volume.traverse_ray(ray_doesnt_intersect) {
        // No hits will be found here.
    }

    println!("Done!");
}

Dependencies

~3.5MB
~118K SLoC