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

判断球心距离是否小于半径之和
两个球体在三维空间中重叠的充要条件是:球心之间的欧氏距离 严格小于 两球半径之和。等于时为外切(不重叠,仅接触),小于才意味着存在公共体积。
实操上别直接开方比较,用平方距离避免浮点误差和 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),但容差不能写死成固定值:
- 对半径较大的球,用相对容差:
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) <p>常见错误包括:<code>center.x - other.center.x</code> 写成 <code>center.x + other.center.x</code>,或把 <code>r + other.r</code> 平方写成 <code>r*r + other.r*other.r</code>(漏掉交叉项)。</p><h3>性能敏感场景下的提前退出</h3><p>如果批量检测(比如碰撞检测系统中每帧检查上千个球),可先做粗筛:用 AABB(轴对齐包围盒)快速排除明显不相交的对,再对候选对做球体精确判断。</p><p>单次判断本身已足够快,但要注意:</p>
- 不要在循环内重复构造临时
Vec3或调用sqrt - 编译器通常能优化掉冗余乘法,但显式写出
(rA + rB)*(rA + rB)比调用pow(rA + rB, 2)更可靠 - 若使用 SIMD,可一次计算多个球对的
dx*dx等分量,但普通项目没必要
真正容易被忽略的是坐标系一致性——比如一个球用世界坐标,另一个用局部坐标却没变换就直接比较,结果完全不可信。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











