wreck 0.2.0

Library for collision detection of 3d shapes
Documentation

wreck

A 3D collision detection library for Rust. Built on top of glam for math and wide for SIMD acceleration.

Traits

  • Collides<T> - boolean collision test between two shapes. Every pair of built-in shapes has an implementation in both directions.
  • Scalable - uniform scaling of a shape.
  • Transformable - translate, rotate (via Mat3 or Quat), or apply a full Affine3 transform.
  • Stretchable - sweep a shape along a translation vector, producing the convex hull of the motion.
  • Bounded - compute bounding volumes: broadphase() (bounding sphere), obb() (oriented bounding box), and aabb() (axis-aligned bounding box). Implemented for all volume types, ConvexPolygon, LineSegment, Pointcloud, and Collider. For Collider, returns infinite bounds if the collider contains any Plane, Line, or Ray.

Shapes

Volumes

  • Sphere - center + radius
  • Capsule - line segment + radius, with a fast path for Z-aligned capsules
  • Cuboid - oriented bounding box (center, 3 axes, half-extents), with fast paths for axis-aligned cases
  • ConvexPolytope - arbitrary convex shape defined by half-planes and vertices, with an OBB broadphase

Surfaces

  • Plane - infinite half-space defined by a normal and offset (normal · x <= d)
  • ConvexPolygon - bounded convex polygon embedded in 3D, defined by a center, normal, and 2D vertices

Lines

  • Line - infinite line through a point with a direction
  • Ray - half-line with an origin and direction
  • LineSegment - finite segment between two endpoints

Primitives

  • Point - a single point in space

Spatial

  • Pointcloud - point cloud backed by a CAPT spatial index for fast broadphase queries

All shape pairs implement Collides<T> for boolean intersection tests. The trait also provides collides_many which can be more performant.

Collider

Collider is a heterogeneous collection of shapes that can be tested against any single shape or another Collider. It supports Transformable, Scalable, applying the operation to every contained shape.

Stretchable is only implemented for Collider since there's no way to stretch a point cloud.

use glam::Vec3;
use wreck::*;

let mut collider: Collider = Collider {
    spheres: vec![Sphere::new(Vec3::ZERO, 1.0)],
    ..Default::default()
};

// add shapes dynamically
collider.add(Cuboid::from_aabb(Vec3::splat(-1.0), Vec3::splat(1.0)));

// test against a single shape
let probe = Sphere::new(Vec3::new(0.5, 0.0, 0.0), 0.2);
if collider.collides(&probe) {
    // hit
}

Shapes API

Creating shapes

use glam::Vec3;
use wreck::*;

// Sphere
let sphere = Sphere::new(Vec3::ZERO, 1.0);

// Capsule — defined by two endpoints and a radius
let capsule = Capsule::new(
    Vec3::new(-2.0, 0.0, 0.0),
    Vec3::new(2.0, 0.0, 0.0),
    0.3,
);

// Cuboid — oriented bounding box
let cuboid = Cuboid::new(
    Vec3::ZERO,                                          // center
    [Vec3::X, Vec3::Y, Vec3::Z],                         // axes
    [1.0, 2.0, 0.5],                                     // half-extents
);
// or from an axis-aligned bounding box
let aabb = Cuboid::from_aabb(Vec3::splat(-1.0), Vec3::splat(1.0));

// Point
let point = Point::new(1.0, 2.0, 3.0);

// Line — infinite, through a point with a direction
let line = Line::new(Vec3::ZERO, Vec3::Y);
let line = Line::from_points(Vec3::ZERO, Vec3::ONE);

// Ray — half-line from an origin
let ray = Ray::new(Vec3::ZERO, Vec3::X);

// LineSegment — between two endpoints
let seg = LineSegment::new(Vec3::ZERO, Vec3::new(1.0, 1.0, 0.0));

// Plane — infinite half-space (normal · x <= d)
let plane = Plane::new(Vec3::Y, 0.0);
let plane = Plane::from_point_normal(Vec3::ZERO, Vec3::Y);

// ConvexPolygon — bounded polygon in 3D
let polygon = ConvexPolygon::new(
    Vec3::ZERO,                                          // center
    Vec3::Z,                                             // normal
    vec![[1.0, 0.0], [0.0, 1.0], [-1.0, 0.0], [0.0, -1.0]],  // 2D vertices
);

// ConvexPolytope — arbitrary convex hull
let polytope = ConvexPolytope::new(
    vec![(Vec3::X, 1.0), (-Vec3::X, 1.0),               // half-planes (normal, d)
         (Vec3::Y, 1.0), (-Vec3::Y, 1.0),
         (Vec3::Z, 1.0), (-Vec3::Z, 1.0)],
    vec![                                                // vertices
        Vec3::new( 1.0,  1.0,  1.0), Vec3::new(-1.0,  1.0,  1.0),
        Vec3::new( 1.0, -1.0,  1.0), Vec3::new(-1.0, -1.0,  1.0),
        Vec3::new( 1.0,  1.0, -1.0), Vec3::new(-1.0,  1.0, -1.0),
        Vec3::new( 1.0, -1.0, -1.0), Vec3::new(-1.0, -1.0, -1.0),
    ],
);

Collision testing

use wreck::Collides;

// pairwise — works in both directions
sphere.collides(&capsule);
capsule.collides(&sphere);

// batch — SIMD-accelerated for some shapes
let others: Vec<Sphere> = vec![/* ... */];
sphere.collides_many(&others);

Transforming shapes

use wreck::{Transformable, Scalable};

let mut sphere = Sphere::new(Vec3::ZERO, 1.0);

// in-place
sphere.translate(Vec3::new(1.0, 0.0, 0.0));
sphere.scale(2.0);

// or get a new copy
let moved = sphere.clone().translated([5.0, 0.0, 0.0]);
let rotated = sphere.clone().rotated_quat(glam::Quat::from_rotation_y(1.0));
let transformed = sphere.clone().transformed(glam::Affine3::IDENTITY);

Bounding volumes

use wreck::Bounded;

// bounding sphere
let bsphere = capsule.broadphase();

// axis-aligned bounding box
let aabb = capsule.aabb();

// oriented bounding box
let obb = capsule.obb();

// works on Collider too — returns infinite bounds if it contains a Plane, Line, or Ray
let collider_aabb = collider.aabb();

Stretching (swept volumes)

use wreck::Stretchable;

// stretching a sphere along a direction produces a capsule
let capsule = Sphere::new(Vec3::ZERO, 1.0).stretch(Vec3::X);

// stretching a cuboid produces either a larger cuboid (axis-aligned case)
// or a convex polytope (general case)
let swept = Cuboid::from_aabb(Vec3::splat(-1.0), Vec3::splat(1.0))
    .stretch(Vec3::new(1.0, 1.0, 0.0));

Features

  • wreck-assert — enables internal assertions in all builds
  • debug-wreck-assert — enables internal assertions in debug builds only