两个球体重叠的充要条件是球心间欧氏距离严格小于半径之和;实际判断时应比较平方距离与半径和的平方,避免开方运算。

判断球心距离是否小于半径之和
两个球体在三维空间中重叠的充要条件是:球心之间的欧氏距离 严格小于 两球半径之和。等于时为外切(不重叠,仅接触),小于才意味着存在公共体积。
实操上别直接开方比较,用平方距离避免浮点误差和 sqrt 开销:
- 设球 A 球心
centerA,半径rA;球 B 球心centerB,半径rB - 计算平方距离:
dx*dx + dy*dy + dz*dz,其中dx = centerA.x - centerB.x等 - 比较:
sq_dist
注意浮点数精度带来的误判
当球体几乎相切(比如 sq_dist 和 (rA + rB)*(rA + rB) 相差 1e-9)时,直接用 可能因舍入误差错判为不重叠或重叠。
稳妥做法是引入容差(epsilon),但容差不能写死成固定值:
立即学习“C++免费学习笔记(深入)”;
- 对半径较大的球,用相对容差:
abs(sq_dist - (rA + rB)*(rA + rB)) - 更常用的是直接判断
sq_dist ,其中 <code>eps = 1e-9适用于单位量级在 1 左右的坐标 - 若坐标可能达 1e6 量级,
eps应设为1e-3或动态计算
结构体封装与常见错误写法
很多人把球定义成 struct Sphere { float x, y, z, r; },但没重载或没写清楚距离计算逻辑,容易在调用时漏掉平方、符号反了、或用曼哈顿距离代替欧氏距离。
推荐最小可行封装:
struct Vec3 {
float x, y, z;
float sq_distance_to(const Vec3& other) const {
float dx = x - other.x;
float dy = y - other.y;
float dz = z - other.z;
return dx*dx + dy*dy + dz*dz;
}
};
struct Sphere {
Vec3 center;
float r;
bool intersects(const Sphere& other) const {
float r_sum = r + other.r;
return center.sq_distance_to(other.center) <= r_sum * r_sum;
}
};常见错误包括:center.x - other.center.x 写成 center.x + other.center.x,或把 r + other.r 平方写成 r*r + other.r*other.r(漏掉交叉项)。
性能敏感场景下的提前退出
如果批量检测(比如碰撞检测系统中每帧检查上千个球),可先做粗筛:用 AABB(轴对齐包围盒)快速排除明显不相交的对,再对候选对做球体精确判断。
单次判断本身已足够快,但要注意:
- 不要在循环内重复构造临时
Vec3或调用sqrt - 编译器通常能优化掉冗余乘法,但显式写出
(rA + rB)*(rA + rB)比调用pow(rA + rB, 2)更可靠 - 若使用 SIMD,可一次计算多个球对的
dx*dx等分量,但普通项目没必要
真正容易被忽略的是坐标系一致性——比如一个球用世界坐标,另一个用局部坐标却没变换就直接比较,结果完全不可信。


















