圆柱体碰撞检测的核心思路是:先计算两圆柱轴线段的最短距离及对应垂足点,再判断垂足是否均落在各自轴线有效高度范围内,最后验证该距离是否小于等于半径之和。

圆柱体碰撞检测的核心思路是什么
C++ 里没有现成的 isCollidingCylinder 函数,得自己算。关键不是“两个立体是否相交”,而是把问题拆解:先看轴线段之间的最短距离,再结合半径判断是否够近。如果两圆柱轴线太远(远于半径和),肯定不碰;否则要检查这个最短距离对应的垂足是否落在各自轴线的有效范围内(即圆柱高度内),并验证该距离 ≤ 半径之和。
实际中,绝大多数场景用的是直立/任意方向的**有限高圆柱体**(capsule-like,但两端是平盖而非球盖),不是无限长的。这点必须明确,否则按无限长算会漏判或误判。
怎么计算两条线段间的最短距离
这是整个检测的性能与精度瓶颈。不能简单取两中心点距离——那只是特例。要用向量投影法求两线段上最近点对 p1、p2,再算 distance(p1, p2)。
推荐直接复用已验证的实现,比如来自 Real-Time Collision Detection(Christer Ericson)书中的 segmentSegmentDistance,或 Eigen 库里的 closest_points_on_segments。手写时注意:
- 必须处理两线段平行、共线、端点重合等退化情况,否则
NaN或除零 - 参数化变量
s和t要 clamped 到[0,1],否则算出的是无限延长线的距离 - 返回的不是标量距离,而是两个最近点坐标,方便后续判断是否在圆柱体内
如何结合半径和高度做最终判定
拿到线段间最短距离 d 和对应点 p1、p2 后,还需两步验证:
第一,确认 p1 在圆柱 A 的轴线范围内:计算它到 A 底面中心的投影长度,判断是否 ∈ [0, heightA];同理验 p2 对 B。
第二,真正决定是否碰撞的条件是:d 。但注意:如果任一最近点落在轴线延长线上(即 clamped 后仍是端点),说明实际最近位置在圆柱的端面上,此时需额外检测点-圆盘距离(即点到端面圆心距离 ≤ 半径,且点在端面法向的正确一侧)。
也就是说,仅靠线段距离不够,必须区分「侧面-侧面」、「侧面-端面」、「端面-端面」三种接触模式。多数轻量级实现只做第一种,会漏掉斜着撞端面的情况。
有没有更实用的近似方案
如果实时性要求高(比如游戏物理),或者圆柱尺寸差异大、角度不极端,可以用 capsule 近似:把圆柱当作两端带半球的圆柱(即 capsule)。此时碰撞检测降维为「两 capsule 是否相交」,有稳定快速的解析解——只需算两轴线段距离,再减去两半径,≤ 0 即碰撞。
但要注意:capsule 是外接近似,比真实圆柱略大,会产生少量误报(false positive);而纯圆柱检测更准,但代码量多 3 倍、分支多、易出错。工程上常先用 capsule 快速剔除,再对少数候选对做精确圆柱检测。
真正难的不是公式,是边界 case:扁平圆柱(height ≈ 0,接近圆盘)、极细圆柱(radius ≈ 0,接近线段)、轴线几乎共面但错开——这些地方浮点误差会被放大,std::abs(d - (r1+r2)) 这类判断必须加 tolerance,且 tolerance 得随尺寸缩放。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











