The rectangles of Part I had their sides along the axes. A box whose edges run along the -, - and -axis is the same idea in space, an axis-aligned bounding box, or AABB, and it’s the shape games reach for first. Its tests use overlap and clamp from the chapter on rectangles, unchanged:
function overlap(a1: number, a2: number, b1: number, b2: number): boolean {
return a1 <= b2 && b1 <= a2;
}
function clamp(value: number, min: number, max: number): number {
return Math.max(min, Math.min(max, value));
}function overlap(a1, a2, b1, b2) {
return a1 <= b2 && b1 <= a2;
}
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}def overlap(a1: float, a2: float, b1: float, b2: float) -> bool:
return a1 <= b2 and b1 <= a2
def clamp(value: float, low: float, high: float) -> float:
return max(low, min(high, value))overlap- time O(1) space O(1)
clamp- time O(1) space O(1)
Boxes as three intervals
Take the box’s corner with the smallest coordinates, , and its width along the -axis, height along the -axis and depth along the -axis. Then the box is nothing more than three intervals:
Every point whose coordinates all fall inside them is in the box.
Point vs box
That’s the test for a point, one axis at a time: is inside when each of its coordinates is inside that axis’s interval.
type Box = { x: number; y: number; z: number; w: number; h: number; d: number };
function pointInBox(p: Vec3, box: Box): boolean {
return (
box.x <= p.x && p.x <= box.x + box.w &&
box.y <= p.y && p.y <= box.y + box.h &&
box.z <= p.z && p.z <= box.z + box.d
);
}// A box is an object like { x: 0, y: 0, z: 0, w: 2, h: 1, d: 3 }.
function pointInBox(p, box) {
return (
box.x <= p.x && p.x <= box.x + box.w &&
box.y <= p.y && p.y <= box.y + box.h &&
box.z <= p.z && p.z <= box.z + box.d
);
}@dataclass
class Box:
x: float
y: float
z: float
w: float
h: float
d: float
def point_in_box(p: Vec3, box: Box) -> bool:
return (
box.x <= p.x <= box.x + box.w
and box.y <= p.y <= box.y + box.h
and box.z <= p.z <= box.z + box.d
)pointInBox- time O(1) space O(1)
Box vs box
Two boxes collide when their intervals overlap on the -axis, on the -axis and on the -axis. If there’s a gap on even one axis, a flat wall fits between the boxes, the way a straight line fitted between two rectangles.
The figure draws each box’s three intervals on the axes. Drag the boxes until they overlap on two axes but not the third, then turn the view: from some angles they look like they touch, and the gap on the third axis says they don’t.
function boxesCollide(a: Box, b: Box): boolean {
return (
overlap(a.x, a.x + a.w, b.x, b.x + b.w) &&
overlap(a.y, a.y + a.h, b.y, b.y + b.h) &&
overlap(a.z, a.z + a.d, b.z, b.z + b.d)
);
}function boxesCollide(a, b) {
return (
overlap(a.x, a.x + a.w, b.x, b.x + b.w) &&
overlap(a.y, a.y + a.h, b.y, b.y + b.h) &&
overlap(a.z, a.z + a.d, b.z, b.z + b.d)
);
}def boxes_collide(a: Box, b: Box) -> bool:
return (
overlap(a.x, a.x + a.w, b.x, b.x + b.w)
and overlap(a.y, a.y + a.h, b.y, b.y + b.h)
and overlap(a.z, a.z + a.d, b.z, b.z + b.d)
)boxesCollide- time O(1) space O(1)
This is the workhorse of 3D collision detection. Engines keep an AABB around every object, and like bounding spheres, only the pairs whose boxes overlap get tested exactly. When an object turns, its box is simply rebuilt around it.
Sphere vs box
Clamping works in space just as it did in the plane: clamp each coordinate of the sphere’s centre into the box’s interval on that axis, and you get , the point of the box closest to . Then it’s point vs sphere.
Watch where goes as you move the sphere: onto a face when the centre is off one face, onto an edge when it’s off two, and onto a corner when it’s off three. When the centre is inside the box, is the centre itself, and the test rightly says they collide.
function closestPointInBox(p: Vec3, box: Box): Vec3 {
return {
x: clamp(p.x, box.x, box.x + box.w),
y: clamp(p.y, box.y, box.y + box.h),
z: clamp(p.z, box.z, box.z + box.d)
};
}
function sphereBoxCollide(s: Sphere, box: Box): boolean {
return pointInSphere(closestPointInBox(s, box), s);
}function closestPointInBox(p, box) {
return {
x: clamp(p.x, box.x, box.x + box.w),
y: clamp(p.y, box.y, box.y + box.h),
z: clamp(p.z, box.z, box.z + box.d)
};
}
function sphereBoxCollide(s, box) {
return pointInSphere(closestPointInBox(s, box), s);
}def closest_point_in_box(p: Vec3, box: Box) -> Vec3:
return Vec3(
clamp(p.x, box.x, box.x + box.w),
clamp(p.y, box.y, box.y + box.h),
clamp(p.z, box.z, box.z + box.d),
)
def sphere_box_collide(s: Sphere, box: Box) -> bool:
return point_in_sphere(closest_point_in_box(s, box), s)closestPointInBox- time O(1) space O(1)
sphereBoxCollide- time O(1) space O(1)
The centre of a box is the midpoint of its two opposite corners, . The next chapter needs it, to test a box against a plane.
Comments
No comments yet. Questions and corrections are welcome.