Skip to content

Collision Detection Module >=26.1

The package dev.anvilcraft.lib.v2.collision provides SAT (Separating Axis Theorem) based collision detection between AABBs and triangle meshes. Supports static overlap detection, per-axis swept collision, and true-direction swept collision.

Performance: 1000 triangles / static 2μs / true swept 67μs

Core API

AnvilLibCollision provides 4 public methods:

intersectsAABBTriangle — Static Collision Detection

Checks whether an AABB overlaps with any triangle in a set.

java
public static boolean intersectsAABBTriangle(
    Vector3dc min,       // AABB min corner
    Vector3dc max,       // AABB max corner
    Vector3fc[] triangles, // Triangle array, vertices[3*i] to vertices[3*i+2]
    double epsilon       // Collision tolerance (gap ≤ epsilon counts as overlap)
)

Returns: true if at least one triangle overlaps with the AABB.
Algorithm: Bounding-box pre-filter (AABB-AABB quick rejection) followed by full SAT with 13 separating axes (3 coordinate + 1 face normal + 9 edge cross-product axes).

intersectsAABBTriangle — Per-Axis Swept Collision

Sweeps the AABB independently along X, Y, and Z axes, computing the maximum safe displacement for each axis.

java
public static Vector3dc intersectsAABBTriangle(
    Vector3dc min,       // AABB min corner
    Vector3dc max,       // AABB max corner
    Vector3dc motion,    // Maximum displacement per axis (components may be positive or negative)
    Vector3fc[] triangles, // Triangle array
    double epsilon       // Collision tolerance
)

Returns: The actual safe displacement vector. Component signs match motion, magnitude ≤ |motion|.

Return ValueMeaning
motion itselfNo collision along entire path
Zero vectorAlready overlapping at start
0 < result < motionCollision encountered during motion

Why per-axis independence: Matches vanilla Minecraft collision behavior — each component is "pushed away" by its respective obstacle, avoiding slope-sliding issues.

sweptCollisionAABBTriangle — True Swept Collision

Translates the AABB along the composite motion direction, finding the displacement at first triangle impact.

java
public static Vector3dc sweptCollisionAABBTriangle(
    Vector3dc min,       // AABB min corner
    Vector3dc max,       // AABB max corner
    Vector3dc motion,    // Displacement vector (direction + magnitude)
    Vector3fc[] triangles, // Triangle array
    double epsilon       // Collision tolerance
)

Returns: motion * t where t ∈ [0,1] is the safe fraction.

t ValueMeaning
t = 1No collision (returns original motion)
t = 0Already overlapping (returns zero)
0 < t < 1Collision encountered during motion

Unlike per-axis sweeping, this method sweeps along the composite motion direction, suitable for precise diagonal collision detection.

overlapOnAxis — Single Axis Projection Overlap

Tests whether a triangle and an AABB's projections overlap on a given axis.

java
public static boolean overlapOnAxis(
    Vector3dc axis,         // Projection axis
    Vector3dc v0, v1, v2,   // Triangle vertices in local space (AABB center already subtracted)
    Vector3dc boxHalfExtents, // AABB half-extents
    double epsilon          // Collision tolerance
)

Usage Example

java
Vector3dc boxMin = new Vector3d(0, 0, 0);
Vector3dc boxMax = new Vector3d(1, 1, 1);
Vector3dc motion = new Vector3d(0.5, 0.3, 0.2);
Vector3fc[] triangles = { ... };
double eps = 0.001;

// 1. Static: is there a collision at the current position?
boolean hit = AnvilLibCollision.intersectsAABBTriangle(boxMin, boxMax, triangles, eps);

// 2. Per-axis sweep: how far can we safely move?
Vector3dc safePerAxis = AnvilLibCollision.intersectsAABBTriangle(boxMin, boxMax, motion, triangles, eps);

// 3. True swept: how far along the composite direction?
Vector3dc safeSwept = AnvilLibCollision.sweptCollisionAABBTriangle(boxMin, boxMax, motion, triangles, eps);

Algorithm Details

SAT — 13 Separating Axes

For each AABB triangle pair, 13 candidate separating axes are tested:

CountTypeAxes
3AABB face normals(1,0,0), (0,1,0), (0,0,1)
1Triangle face normalf0 × f1
9Edge cross-product axesAABB edge × triangle edge

If any axis separates the two projection intervals, there is no collision.

Bounding Box Pre-Filter

Before full SAT, a quick AABB-AABB rejection test discards triangles whose bounding boxes don't intersect the target, dramatically reducing the number of cross-product computations.

Per-Axis vs True Swept

ModeMethodApproachUse Case
Per-axisintersectsAABBTriangle(min,max,motion,triangles,eps)Sweep along X/Y/Z independentlyVanilla Minecraft physics, block collisions
True sweptsweptCollisionAABBTriangle(min,max,motion,triangles,eps)Sweep along composite motionPrecise diagonal collision, projectile detection

Benchmark

Test conditions: AABB (0,0,0)→(2,2,2), motion (0.5,0.3,0.2), epsilon=0, triangles randomly distributed in [-10,12] cube, ~50% intersecting.

TrianglesStatic SATPer-Axis SweptTrue Swept
185 ns361 ns197 ns
10145 ns2.1 μs654 ns
1002.0 μs21.9 μs10.3 μs
100012.3 μs260 μs67.0 μs
10000161 μs2.17 ms841 μs

Test Coverage

CollisionTest includes 40 test cases (all passing):

GroupTests
A: Static DetectionInside, outside ±X/±Y/±Z, piercing, touching face, gap tolerance, point, line, triangle contains AABB, batch intersect, batch no intersect, cross-axis, negative-extent AABB (17)
B: Single AxisOverlap, separated, gap eps=0, gap eps=0.01 (4)
C: Per-Axis SweptNo obstacle ±X/±Y/±Z, blocked, initial overlap→0, one-way blocked other free, gap tolerance, moving away, diag blocked X+Y (10)
D: True SweptAxis-aligned blocked, diag slides past narrow wall, initial overlap, diag no obstacle, large wall diag blocked, zero motion, gap tolerance (7)

Dependency

groovy
dependencies {
    implementation "dev.anvilcraft.lib:anvillib-collision-neoforge-26.1:2.0.0"
}

Notes

  • All methods use Vector3dc/Vector3fc (JOML) — ensure correct precision types
  • epsilon controls collision strictness: 0 = contact-only collision; larger values provide earlier "sensing"
  • Triangle array length must be a multiple of 3
  • Per-axis sweeping most closely matches vanilla Minecraft collision behavior
  • True swept is suitable for precise diagonal collision scenarios, with slightly lower performance than per-axis

Released under the CC-BY-NC-SA 4.0 License.