球体碰撞的判定条件是球心距离平方 ≤ 半径和的平方。具体为:计算dx²+dy²+dz²(dx=x1−x2等),与(r1+r2)²比较,避免开方以保精度与性能。

判断球体碰撞的核心逻辑是距离比较
两个球体发生碰撞,当且仅当它们的球心距离 ≤ 两球半径之和。这不是近似,而是精确的几何判定条件——只要算对了欧氏距离,结果就绝对可靠。
关键陷阱在于:**别开平方根**。直接比较距离的平方,避免 sqrt 带来的浮点误差和性能损耗。
- 设球 A 球心为
(x1, y1, z1)、半径r1;球 B 为(x2, y2, z2)、半径r2 - 计算平方距离:
dx*dx + dy*dy + dz*dz,其中dx = x1 - x2等 - 比较:
dx*dx + dy*dy + dz*dz
用 glm::vec3 时注意成员访问和精度
如果项目已用 GLM(常见于图形/游戏开发),直接用 glm::distance 看似方便,但它内部调用了 sqrt,且返回 float —— 在高速物理更新循环中不推荐。
- 更优写法是手写平方距离:
glm::length2(centerA - centerB) -
glm::length2返回float,若用double半径需显式转换,否则可能触发隐式降级 - 确保两个
glm::vec3使用相同精度模板参数,比如都用glm::dvec3处理高精度需求
浮点误差导致的“穿模”或“误触”怎么防
纯数学上成立的判定,在浮点运算下可能因累积误差失效——尤其当球体高速运动、单帧位移远大于半径时,会跳过碰撞区间(tunneling)。
立即学习“C++免费学习笔记(深入)”;
- 基础碰撞检测只适用于「帧间位移小于两球半径之和」的场景
- 若出现漏判,必须升级为连续碰撞检测(CCD),即求解球心连线与相对速度构成的线段-球交点
- 简单缓解:在判定前加一个极小容差,如
eps = 1e-6f,写成sqDist ;但仅治标,不能替代 CCD
2D 场景下可以省掉 z 轴计算
如果所有球体都在同一平面(比如俯视角游戏),强行用 3D 向量计算会多算一次 dz*dz,虽开销小,但无必要。
- 直接用二维坐标:
(x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) - 若数据结构里存的是
glm::vec3但 z 恒为 0,仍建议提取.x和.y手算,避免编译器未必能优化掉冗余的 z 分量 - 注意:不要用
glm::length2(vec2)混用类型,GLM 对vec2和vec3是不同类型的模板特化,类型不匹配会编译失败
实际工程中,最常被忽略的是帧间位移检查——写完 isColliding() 就以为万事大吉,但没验证运动速度是否在安全范围内。


















