关于碰撞检测和物理引擎
早期3D游戏的碰撞检测多数基于格子或者BSP树,基于格子的系统实现简单但精度不够,不属于严格意义的3D碰撞检测。基于BSP树的碰撞检测一度十分流行,算法基本已经成熟定型,但是BSP树需要很长的预处理时间不适合加载时计算,管理大型的室外场景很是费力。目前对于任意复杂三角形集合(mesh)的碰撞检测多数基于BVTree(bounding volume tree),具体可以是aabb tree,obb tree或者K-dop tree,这也是当今各种物理引擎和碰撞检测引擎流行的做法。
AABB:轴对齐包围盒也被称作矩形盒。
OBB,有向包围盒,是一个可以任意旋转的AABB
k-DOP 离散的有向多面体,由k/2个归一化法线定义。
上面是碰撞检测按数据结构不同的分类,按检测方式又可以分为离散点的碰撞检测和连续碰撞检测(CCD continuous collision detection)。离散点的碰撞检测是指定某一时刻T的两个静态碰撞体,看它们之间是否交迭,如果没有交迭则返回它们最近点的距离,如果交迭则返回交迭深度,交迭方向等。连续碰撞检测则是分别指定在T1、T2两个时刻两个碰撞体的位置,看它们在由T1运动到T2时刻的过程中是否发生碰撞,如果碰撞则返回第一碰撞点的位置和法线。连续碰撞检测是最为自然的碰撞检测,可以大大方便碰撞响应逻辑的编写,可以很容易避免物体发生交迭或者穿越。离散点的碰撞检测则没有那么友好,当检测到碰撞时两个物体已经发生了交迭,如果其中有三角形网格对象那么已经有许多三角形发生了交迭,如何将两个交迭的对象分开并按合理的方式运动是一个挑战。虽然连续碰撞检测是最自然的方式,但它的实现非常复杂,运算开销也很大,所以目前大部分成熟的物理引擎和碰撞检测引擎还是采用了基于离散点的碰撞检测,为了避免物体交迭过深或者彼此穿越,它们都要采用比较小的模拟步长。
从一个角度讲,物理模拟分为两部分,碰撞检测和模拟计算。你要模拟的东西不是单独的,而是充分交互的,或者说交互才是模拟的核心。既然要交互,碰撞检测是必不可少的部分,实际上,就代码量而言,一个物理引擎所包含的碰撞检测的代码一般都会多于模拟计算的代码。因为相对来说,后者所面对的问题要单纯一些。从另一个角度来说,物理模拟还是分成两部分,数学建模和数学求解。其实这也是用数学处理实际问题的一般规律。当我们建立好空间,位置,速度的数学表示,是建模的过程;而在每个time_step中,对速度和位置的改变(包括碰撞时的改变),则是求解的过程。比如说为什么碰撞的时候,把Y向速度反向呢?因为这就是求解的结果。(当然这个结果是非常粗糙甚至是在某些情况下有问题的)。
关于物理引擎,碰撞检测一般分成三个部分,粗测阶段(BroadPhase),细测(NarrowPhase)和中间(MiddlePhase),所谓BroadPhase,就是对所有的Shape进行初步检测,具体做法是检测每两个Shape的包围盒是否相交,是则送入下一阶段处理。这里的包围盒一般是AABB,原因显然是它的性价比最好。下一步就是NarrowPhase了,这时,我们必须根据不同类型的Shape给出不同的算法。在物理引擎中,碰撞检测的工作并不是到找到哪些Shape相交就结束了。还有很多工作要做,我们要选取合适的碰撞点,对每个碰撞点要得到法线,相交深度等信息。
作者:康斯特
个人WIKI(常年更新):http://dev.wannaplay.cn/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
期待技术交流,共同进步