RealTime-Rendering12-AABB Plane intersection

AABB Plane intersection

核心判定逻辑:计算AABB中心到平面的有符号距离(signed distance),并与AABB在平面法线方向上的投影半径(projection interval radius)进行比较。

平面由法向量n和到原点的距离d定义:

$x\cdot \vec{n} = d$

AABB由最小角点 min 和最大角点 max 定义,可以将其转换为中心-半边长(center-extents)表示:

中心点:$c = (min + max) / 2$

正半边长:$e = max - c$

投影半径计算:

AABB在平面法线n方向上的投影半径r为各轴向半边长在法线方向上的绝对值之和,这实际上是AABB在法线方向上的最大”半径”——从中心到最远顶点的投影距离,直观理解可以表示为AABB在法线方向投影的覆盖范围

$r = e_x|n_x| + e_y|n_y| + e_z|n_z|$

有符号距离计算:

计算AABB中心 c 到平面的有符号距离 s:

$s = \vec{n} \cdot c - d$

条件 结果 含义
$\lvert s \lvert <= r$ 相交 AABB与平面相交或接触
$s < -r$ 完全在负侧 AABB完全位于平面负半空间
$s > r$ 完全在正侧 AABB完全位于平面正半空间

几何解释:投影半径$r$定义了一个区间$[-r, +r]$。如果中心到平面的距离$s$落在这个区间内,说明平面穿过AABB;否则AABB完全位于平面的一侧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Test if AABB b intersects plane p
int TestAABBPlane(AABB b, Plane p)
{
// Convert AABB to center-extents representation
Point c = (b.max + b.min) * 0.5f; // Compute AABB center
Point e = b.max - c; // Compute positive extents

// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = e[0]*Abs(p.n[0]) + e[1]*Abs(p.n[1]) + e[2]*Abs(p.n[2]);

// Compute distance of box center from plane
float s = Dot(p.n, c) - p.d;

// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}

01.png