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.