两个三维球体相交当且仅当球心距离小于等于半径之和,即 distance ≤ r1 + r2;推荐用平方距离比较以避免 sqrt 引入的精度与性能问题。

球心距离小于半径之和就是相交
判断两个三维球体是否相交,本质是看它们的球心距离是否小于等于两球半径之和。严格来说,distance ≤ r1 + r2 时相交(含外切);若要求“有重叠体积”,则用 distance (排除仅相切的情况)。
注意:不需要开方运算——直接比较平方距离和半径和的平方,避免浮点误差和 sqrt 开销。
distance_squared = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2)-
sum_radius = r1 + r2,然后比较distance_squared - 若任一球半径为负,行为未定义;应提前校验
r1 >= 0 && r2 >= 0
用 glm::length 和 glm::distance 容易踩精度坑
如果项目用了 GLM(OpenGL Math),别直接用 glm::distance(a, b) 再跟 r1 + r2 比——它内部调用 sqrt,引入额外浮点误差,且性能略差。
更稳妥的是手算平方距离,或用 glm::length2(a - b)(返回平方长度,无开方):
立即学习“C++免费学习笔记(深入)”;
glm::vec3 center1 = ..., center2 = ...; float r1 = ..., r2 = ...; float dist_sq = glm::length2(center1 - center2); bool intersect = dist_sq <= (r1 + r2) * (r1 + r2);
-
glm::length2是安全的,但确保向量类型一致(如全用glm::vec3,别混float和double) - 若用
double精度球体数据,而 GLM 默认是float,可能截断——显式指定glm::dvec3并用glm::length2对应重载
包含关系(一个球在另一个内部)也算相交吗?
数学上,“相交”通常指集合交集非空,所以一个球完全在另一个球内(甚至同心)仍算相交。此时条件仍是 distance + min(r1, r2) >= max(r1, r2),等价于 distance 且 <code>distance >= abs(r1 - r2) 不必额外判断——原不等式已涵盖。
- 例如:
center1 == center2且r1 = 5, r2 = 3→distance = 0,0 成立,相交 - 若需区分“部分重叠”和“包含”,才要额外检查
distance + std::min(r1, r2) - 多数碰撞检测场景(如物理引擎)把包含视为有效相交,无需拆分逻辑
浮点数比较时要不要加 epsilon?
对绝大多数工程场景,直接用 即可。只有当球体参数本身来自大量迭代计算、累计误差明显(比如 > 1e-6),才考虑加 epsilon。
- 稳妥写法:
dist_sq - 但注意:epsilon 要跟数值量级匹配——若球半径是 1e6 级,1e-9 就太小;此时用相对误差或直接避免依赖精确相等
- 真正容易出问题的是“恰好相切”这种边界情况;如果业务逻辑对相切敏感(比如触发事件),建议统一按
判断重叠,相切归为“不相交”
球体相交判断本身很稳定,复杂点在于你怎么定义“相交”——是几何定义、物理碰撞,还是渲染剔除需求。边界处理方式得跟着用例走,而不是套公式。


















