高级碰撞检测技术

1649 篇文章 12 订阅
1623 篇文章 23 订阅
Advanced Collision Detection Techniques
-------------------------------------------------------------------------
高级碰撞检测技术
-------------------------------------------------------------------------
Nick Bobic
-------------------------------------------------------------------------
Zhaott(zhaott@hotmail.com)阅读翻译
-------------------------------------------------------------------------
  从计算机游戏出现以来,程序员就想尽办法更逼真模拟世界。例如 Pong 展现了运动正方形(球)和两个板。游戏者要正确移动板,将球反弹到对手方向。这个基本动作的依据就是(按照今天的观点看)就是碰撞检测。今天的基于3D的游戏比 Pong 更先进了。实现3D中的碰撞检测比2D游戏 Pong 更困难。早期飞行模拟的体验经验告诉我们不好的碰撞检测使得游戏如此糟糕。飞过山峰依然存活是非常不真实的。尽管现阶段的游戏改进了碰撞问题。玩家依然对男女主角的身体部分进入墙壁感到不适应。更糟糕的是很多玩家有被“不接近”他们的火箭或子弹击中的体验。因为今天的玩家要求增加真实感,我们开发要努力实现游戏中接近现实世界。
  本文假定读者了解碰撞检测涉及到的一些基本几何和数学知识。本文的后面部分为生疏者提供了一些参考资料。同时假定你已经阅读 Jeff Lander 的关于碰撞检测的图像专栏文章(“Crashing into the New Year,” ; “When Two Hearts Collide,”;    “Collision Response: Bouncy, Trouncy, Fun,”)。我自上而下展示碰撞检测,首先  整体了解,然后学习核心过程。我从两个类型的图像引擎讨论碰撞检测:轻量级引擎和  BSP级引擎。因为每种引擎中的几何组织很不相同,世界对象碰撞检测技术也很不同。
  物物碰撞检测很大程度上依赖于你的实现,可以做到各类型相同。在我们了解多变形检测  后,我们会扩展到曲面对象。
  ------------------------------------------------------------------------
大流程图
  为了开发最佳碰撞检测流程,在我们开发游戏图形管线时应该开始计划和创建基本构架。在项目接近结束时增加碰撞检测是非常困难的。在开发后期增加快速碰撞检测可能毁掉整个游戏,因为很难做到高效。在优秀的游戏引擎中,碰撞检测应该准确,高效和快速。这些要求意味碰撞检测通常同场景几何管理管线紧密联系。暴力方法不起作用了,今天游戏中每祯要处理的数据大得惊人。如果在场景中检查对象每个多变形相互作用,时间不允许。
  然我们来看看游戏引擎的基本循环。浏览后就体会到碰撞检测的策略。我们假定碰撞没有发生,更新物体位置。如果发现碰撞发生,我们反回移动,不允许他们穿越边界(或者破环他们,或者其他预防措施)。当然这个假定很简单,因为我们不知道之前的位置是否可用。你应该针对这种情况制定规则(否则会崩溃,或者顶住)。如果你是个热情的玩家,在某些游戏中你会发现,当你接近墙面并试图穿越它的时候,画面会抖动。这些体验是角色反回移动的效果。抖动是粗略的时间跨度结果(时间片)。
  但是我们的方法更糟,我们方程中没有时间量。图1表示了时间是如此重要,不能忽略。尽管t1或t2对象不会碰撞,但是存在t1<t<t2的时间t,他们仍会穿越边界。这种情况在连续祯跨度很大时存在(当角色遇到火网等物体)。我们必须找到妥善的解决方法。
  我们可以把时间最为第四维变量考虑,在4D中计算。这样计算过于复杂,不适合应用。我们也可以将时间t1和t2的原始对象关联形成实体,然后检测实体同墙(图2)。  一个可行的方法是在两个不同时间环绕对象位置创建一个凸壳。这个方法低效,会减慢游戏运行。我们可以环绕实体创建边框。但我们熟悉了其他技术后再回头讨论这个问题。
  另一个容易实施但是准确性不高的方法是将时间间隔减少到一半,在中点检测相交。这个方法可以递归操作。这个方法比前一个方法快,但不能保证捕捉所有碰撞。
  另一个隐含问题是 collide_with_other_objects() 过程,他用来检测场景中一个对象是否和其他对象相交。如果场景中有太多对象,这个过程很耗时。如果不得不每个对象同场景中其他对象是否相交,这样做要产生Cn2次比较。这样我们需要做得比较数是N2级(O(N2))。但是我们可以用其他方法避免O(N2)两两比较。例如我们将世界划分为静止不动的被撞击者和即使v=0的运动的撞击者。例如,房间中的固定墙壁是被撞击者,在墙上弹射的网球是撞击者。我们在这些对象上建立两个空间树(每类一个),接下来检测那些对象有碰撞可能性。我们同时可以在环境中增加限制,使得两个碰撞者不能发生碰撞。例如不用计算两个子弹的碰撞。现在,让我们假设,这个过程对我们已经比较清晰了。(在场景中避免两两比较的另一个方法使创建八叉数,这个议题超出了本文范围,你可以阅读《Spatial Data Structures: Quadtree, Octrees and Other Hierarchical Methods》
它在文章后面的进一步信息一节中提到八叉树)。现在我们考虑轻量级引擎,看看碰撞检测的困难所在。
-------------------------------------------------------------------------
轻量级引擎,物物碰撞
  轻量级引擎将场景或世界分成小的凸多边形部分。由于消除了透过,凸多边形更适合图形通道。不幸的是凸多边形为碰撞检测带来了困难。在我最近的测试中,一个普通的凸多边形部分包括了400-500个角。当然,由于不同引擎使用不同的几何技术创建部分。这个个数有所变化。角的个数也随着层或世界不同而变化。确定对象的角穿透世界多边性要耗费大量计算。碰撞检测的基本方法是用圆逼近对象或对象部分,检测圆球的相交。由于计算耗费低,这个方法今天依然被广泛应用。我们只须计算两个圆的中心距离小于半径和(预示碰撞发生)。甚至我们只需要计算距离平方小于半径平方和,避免距离计算的开方计算。当然这样计算简单,结果不是准确的(图3)。但是我们可以用不准确的方法作为第一步。我们将一个大球替代角色,然后检测同场景中其他对象是否相交。如果检测到碰撞就增加精度。我们将大球减小为一组小球,依次检测碰撞情况(图4)。我们不停减少和检测满足策略需要。这
种层次和细分思想是我们需要完善满足需要的。
  用球接近对象计算耗时少,但是游戏中的很多几何体是正方形,我们应该用矩形框接近对象。开发者长期使用边界框和递归分割加速各种光线跟踪过程。特别是这个方法可以用八叉树和轴对齐边界框(AABB)。图5给出了一个AABB及其中的对象
  “轴对齐”指边框同世界坐标对齐,或者边框的面垂直于一个坐标轴。这样减少边框转换的计算。AABB在许多游戏中应用。开发者经常把他们认为是模型的边框。这个速度折衷方案是准确的。由于AABB是轴对齐的,对象旋转时他就不仅仅是旋转了---每祯,他们要重新计算。而且计算不是困难的,如果知道角色模型的范围,不会减低速度。当然,我们一样面临精度考虑。例如,假设我们刺一个细直的棒,我们为动画每祯构建一个AABB。我们看到边框每祯都不同,精度也在变化(图6)。
  所以,为什麽我们不能用任意导向和最小空余的边框,或者有问题,作为边框近似。这个方法基于导向边框(OBB)技术并被用应用到光线跟踪和干涉检查很长时间了。这个方法不太精确,但是我们会看到他比AABB技术更强健。尽管OBB实现比较困难,速度慢,不适于动力学和可编程模型(例如可变体对象)。重要的是当我们将对象地减为更小的片,我们可以创建该对象的层次数。
  选择AABB 和 OBB 的标准是需要的精度级别。对快速动作3D射击者,我们最好实现AABB碰撞检测---为了实现容易和速度可以牺牲精度。本文相应的源码可以在Game Developer找到。你应该从一些碰撞检测包提供的同时也包括OBB代码做例子学习AABB。现在我们了解了工作的基本思想,来看看实现。
-------------------------------------------------------------------------
建立树
  从任意网格创建OBB树是算法最困难的部分,应该适应引擎或游戏类型。图7展示了从开始连续OBB的创建。正如你所见,我们要找到环绕给定模型(顶点集合)的紧密边框(3D中容积)。
  有许多方法预先计算OBB,需要用到很多数学知识。基本的方法是计算顶点的分布的中值作为边框中心,然后计算协方差矩阵。我们使用协方差矩阵三个特征值中的两个作为边框的几何特征。我们同时用凸壳过程加速优化树的创建。这些可以在Gottschalk, Lin, 和 Manocha 的论文 “更进一步信息”部分找到。
  创建AABB树更简单,因为不需要找到最小环绕体积和他的轴。我们只需要决定在那里分割模型,自由创建边框(因为边框平行于坐标轴,在分离的平面一侧中包括了所有顶点)。
  现在,我们创建了所有边框,可以创建树了。我们采用自上而下的方法,从开始块递减下去。另外,我们也可以采用自下而上的方法,从小块到大块。为了将大块分成小块,要遵循一些规则。
  像你看到的,创建过程相当复杂,包括了大量运算。在运行时一定不能及时创建这个树---他们必须要预先创建。树的预先计算消弱了运行时几何变换的机会。另外一个缺点是,OBB需要大量矩阵运算。我们必须将他们放置在空间中,每个子树必须和矩阵相乘。
-------------------------------------------------------------------------
用分层树检测碰撞
  现在我们假定OBB 或 AABB 树已经存在。我们如何做碰撞检测?我们拿到两个树,检测两个初始边框是否重叠。如果他们重叠,就可能相交,我们需要进一步递归处理(向下递归)。在向下递归中,如果发现子树不相交了,我们就可以停止并得出不相交结论。如果子树相交,我们就处理数直到叶子节点,找到那一部分重叠。所以,唯一需要指出的就是如何检查两个边框重叠。我们需要做的测试之一是将边框映射到空间一个坐标轴上,检查区间是否相交。如果不相交,给定轴称为分离轴(图8)。
  为了快速检查重叠,我们使用分开轴理论。这个理论告诉我们,我们只考虑15个潜在分离轴。如果每个分离轴都发生重叠,边框相交。这样很容易确定边框是否相交。
  有趣的是,前面提到的时间跨度问题用分离轴技术很容易解决。这个问题是决定任意两个给定时间内碰撞是否发生。如果在边框映射区间增加速度,他们在15个轴相交。碰撞会发生。我们也可以使用类似AABB树的结构,区分碰撞者和被碰撞者,检查他们相交的可能。这种计算可以很快摒弃一个场景中多数情况,优化到O(NlogN)级别。
-------------------------------------------------------------------------
基于BSP树的碰撞技术
  BSP(二元空间分割)树是游戏业使用多年的另一种空间细化技术(Doom是第一个使用BSP树的商业游戏)。尽管今天BSP树不比数年前流行,三个畅销游戏引擎---Quake II, Unreal, 和 Lithtech 依然使用它。当我们考虑到碰撞检测,BSP树的优点和高效依然闪亮。BSP树不仅对几何裁剪高效,对世界对象碰撞检测也高效。
  BSP树遍历是BSP树的重要基础。碰撞检测简化为BSP树遍历或搜索。这个方法很强大,因为它预先提出了许多几何特征,最终,我们只需要检测少数几个平面的碰撞。我们之前看到的,查找两个对象之间的分离平面已经足够判断两对象不相交了。如果存在分离平面,没有碰撞发生。所以我们可以递归遍历一个世界树,检查分离平面是否同环绕球或环绕框相交。我们也可以通过检查对象多边形的每个面提高精度。检查很简单,只需要检测对象的所有部分是否在平面同一侧。这个计算相当简单。我们可以用笛卡尔平面方程ax + by + cz + d = 0 确定点所在的位置位于平面那一侧。如果方程满足,点在平面上,如果ax + by + cz + d > 0,点在平面正侧,如果ax + by + cz + d < 0,点在平面负侧。
  最需要一提的是碰撞没有发生的情况,对象(环绕框)的所有点在给定平面的正侧或者负侧。如果既有点在平面正侧又有点在平面负侧,碰撞发生,平面同给定对象相交。
  不幸的是我们没有合适的方法检测两个区间之间是否相交(尽管开头讨论的方法仍可以用)。所以我们来看BSP树经常使用的另一个结构。
-------------------------------------------------------------------------
弯曲物体和碰撞检测
  现在我们看看多边形对象碰撞检测的两个方法。让我们看看弯曲物体如何计算碰撞。1999年,几个游戏大量使用弯曲曲面,所以在新的一年里,有效的弯曲曲面碰撞检测很重要。弯曲曲面碰撞检测(包括了给定点的精确曲面)要求极强的计算精度,要避免这种情况。这种情况,我们已经有了好几种方法。最明显的方法是用最低密铺代表模拟曲面,用这个多面体做碰撞检测。一个低精度的更容易的方法是在曲面控制顶点外创建一个凸壳用来做碰撞检测。在各种情况中,曲面碰撞近似为普通的多面体做碰撞检测。图9是曲面和控制顶点的凸壳。
  如果我们混合使用这些技术,我们首先检测同壳的碰撞,逐步细化到壳代表的部分。这样极大地提高了精度。
-------------------------------------------------------------------------
自己决定
  现在,我们了解了一些高级碰撞检测构成(也是一些基本的),你可以决定那一种类型最适合你的游戏。你主要要考虑的是为了速度,实施简单(少的开发时间)和扩充使用怎样的精度。
-------------------------------------------------------------------------
更多的信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值