判断两球重叠只需比较球心平方距离与半径和的平方:若前者≤后者则重叠(含相切),避免开方;需注意数值溢出、浮点误差、非均匀缩放导致椭球失效等问题。

判断两个球体是否重叠的核心逻辑
两个三维球体是否重叠,只取决于它们的球心距离和半径之和。如果球心距离小于等于两半径之和,就重叠(含相切);否则不重叠。
关键点在于:不需要开方运算——直接比较平方距离和半径和的平方,避免 sqrt 带来的浮点误差与性能损耗。
常见错误是写成 distance 却没对距离做平方处理,导致逻辑错乱;或者误用绝对值、逐轴比较等错误方式。
C++中计算球心距离平方的实操写法
假定每个球体用结构体表示,含 center(std::array<float></float> 或自定义 vec3)和 radius(float):
立即学习“C++免费学习笔记(深入)”;
struct Sphere {
std::array<float, 3> center;
float radius;
};
<p>bool overlap(const Sphere& a, const Sphere& b) {
float dx = a.center[0] - b.center[0];
float dy = a.center[1] - b.center[1];
float dz = a.center[2] - b.center[2];
float dist_sq = dx<em>dx + dy</em>dy + dz<em>dz;
float r_sum = a.radius + b.radius;
return dist_sq <= r_sum </em> r_sum;
}</p>注意:dist_sq 和 r_sum * r_sum 都是 float 类型,若半径很大(比如 > 1e4),平方后可能溢出;对高精度或大范围场景,应改用 double。
- 避免用
std::hypot:它内部调用sqrt,且为防溢出做了额外缩放,完全没必要 - 不要用
std::abs对每个分量取绝对值再加——这不是欧氏距离 - 若球心坐标来自变换矩阵输出,需确认是否已归一化或存在数值抖动,必要时加小阈值(如
1e-6f)容忍浮点误差
当球体带旋转或非均匀缩放时不能直接套用
上述方法仅适用于**标准球体**(各向同性、未变形)。一旦模型经过非均匀缩放或旋转,其实际形状是椭球,此时 Sphere 结构已失效。
此时必须切换思路:
- 要么将椭球反变换回单位球,再用相同逻辑判断(需逆变换矩阵)
- 要么使用通用碰撞库(如
bullet或geomc)中的OBB/ellipsoid检测 - 绝不可把椭球中心当球心、长轴当半径硬套公式——结果必然漏判或误判
一个典型陷阱:导出的 glTF 模型中 scale 属性影响包围球,但加载器未必自动修正 boundingSphere,需手动校验。
性能敏感场景下的优化提示
在每帧检测上千对球体(如粒子系统)时,基础版本仍可能成为瓶颈。可考虑:
- 先做粗筛:用
axis-aligned bounding box (AABB)快速排除明显不重叠的对(只需 6 次减法 + 比较) - 批量计算:将球心坐标存为 SoA 格式(如三个独立的
std::vector<float></float>),利于 SIMD 向量化 - 早退出:若使用循环遍历,对
dist_sq计算后立即判断,别攒一堆再比
真正容易被忽略的是:浮点比较的鲁棒性。当两球几乎相切时,dist_sq == r_sum * r_sum 几乎不可能成立,应始终用 ,而非 <code>== 或单独处理相切。


















