reference:《Real-Time Rendering》

目录

17   前言

17.1 和射线的碰撞检测

17.2 使用BSP树的动态碰撞检测

17.3 一般层次的碰撞检测
  17.3.1 分层的构建

17.3.2 不同层之间的碰撞检测

17.3.3 代价函数

17.4 OBB树

17.5 多重物体碰撞检测系统

17.5.1 广阶段的碰撞检测

17.5.2 总结

17.6 更多样的话题

17.6.1 及时碰撞检测

17.6.2 距离查询

17.6.3 可变形的模型

17.6.4 碰撞响应

17.6.5 基于GPU的碰撞检测

一般层次的碰撞检测

这一部分将会展现检测两个给定模型的碰撞检测算法中一般的方法。这些算法有前言中介绍的4个特点。这些算法的共性是:

○ 为每个模型创建一个包围盒。
        ○ 碰撞查询的高层次的代码是类似的,不管使用了哪种包围盒。
        ○ 可以使用一个简单的代价函数来修剪、评估以及比较算法表现。
        这些点在接下来的三个小部分中具体涉及。

分层(hierarchy)的构建

一开始,一个模型是由一系列基元(primitives)表达的,在我们的例子中是多边形集合,对于多于三个顶点的多边形,我们都把它分解为多个三角形(看第12章)。然后,由于每个模型都需要用一种类型层次的包围盒来表达,我们需要一个创建有我们期望性质的层次的方法,通常在碰撞检测算法中使用的层次是一个叫做k-ary树的数据结构,它的一个结点最多有k个孩子(看第14章)。许多算法都使用了k-ary树最简单的形式,也就是二分树,其中k=2。在每个内部结点中,都有一个包住它的所有孩子的包围盒,并且在每个叶结点处都有一个或多个基元(在这个例子中,是三角形)。任意结点的包围盒(无论是叶结点还是内部结点)A,记为 ,属于A的孩子集合记为

主要有三种的方式来创建一个分层:自底向上的方法,渐进树插(incremental tree-insertion),或者自顶向下方法。为了创建更有效,包得更紧的结构体,我们总是尽可能减少包围盒的区域以及体积。对于碰撞检测,缩小包围盒体积是有意义的,因为一个包围盒需要和另一个包围盒进行检测。其中第一种自底向上的方法,是从合并基元并为它们寻找包围盒开始的。这些基元应当靠得足够近,这可以由基元之间的距离来衡量。然后,新的包围盒要么是以同样的方式创建的,要么是使用已存在的包围盒和一个或多个其它包围盒用相似的方式构建在一起,因而产生了一个新的,更大的父包围盒。我们不断重复这一步,直到只存在一个包围盒,它就成为这个分层的根节点。在这种方式下,靠得近的基元总是与在包围盒里与彼此接近。Barequest et al. Present BOXTREE(???),一个可以执行光线追踪和碰撞检测数据结构,就是自底向上构建的。

渐进树插方法是从一棵空树开始的。然后剩下的基元以及它们的包围盒是一个个插入到树中的。下图中有了具体的阐释。为了创建高效的树,我们需要找到树上的一个插入点。我们应当选择使得整个树体积增加最慢的点。达到这一点的一个简单的方法是,我们下降到树中有更小增长的孩子。这一类的算法通常要花费O(nlogn)的时间。打乱基元插入的顺序可以使树的形成结构更好。对于更复杂的方法,可以看Omohundro的一些作品。它在碰撞检测这一内容里并不涉及渐进树插,但是渐进树插已经在光线追踪以及相交查询中有比较好的成果了,所以它对碰撞检测而言运行的效果也应当一样好。

左图中,显示了一个有三个结点的二叉树。我们假设每个叶结点只存储了一个基元。现在我们想要插入一个新的结点,叫做N。这个结点包含一个包围盒,包围盒中有一个基元。因此,这个结点会作为叶结点插入。在这个例子中,如果我们在C处插入N结点的话(而不是B),我们认为我们找到了更小的树体积,然后创建一个包含C和新节点N的新的父节点P。

用于大多数分层构建算法的自顶向下方法,是由找到模型的所有基元的包围盒开始的,它被当做树的根节点。然后再使用分治的方法,包围盒首先被分为k个或者更小的部分。对于每个部分而言,我们找到其包含的所有基元,然后再以和根同样的方式创建包围盒。i.e.分层是递归创建的。通常会去找基元被划分时应当沿着的坐标,然后再在这个坐标上找一个好的划分点。在第16章第四部分讨论了几何概型,这可以用于在坐标轴上搜索好的分割点,这样就能得到更好的包围盒。注意自顶向下方法的一个潜在优点是可以惰性创建一个层,i.e.根据需要的基础上。这意味着我们仅仅为真正需要的场景部分创建层。但是由于这一创建过程是在运行时完成的,当层次的一部分创建出来后,性能会大幅度下降。这对于要求实时性的游戏一样的应用是不能接受的,但是对于CAD应用或者像路线规划、动画以及其它的离线计算而言,则节省了大量的时间和内存。

碰撞检测算法的一个挑战是找到更紧的包围盒以及能创建出更平衡更高效的树的方法。注意在所有情况下,平衡树的平均性能是最好的,因为每个叶结点的深度都是一样的(或者几乎是一样的)。这意味着它在层向下遍历到叶的时候花费相等的时间,碰撞查询的时间不会随着叶结点的不同而变化。在这样的情况下,平衡树是最优的。但是,这并不意味着它对所有的输入都是最好的。例如,如果模型的某一部分很少或者从不涉及到碰撞查询,那么这一部分可以在不平衡树中处在比较深的位置,所以查询更频繁的部分可以更接近于根。这一OBB树过程的细节在第四部分有具体介绍。

同样注意,在第14章第一部分介绍了一些空间数据结构的加速算法,包围盒的创建则在16章第三部分介绍。

不同层之间的碰撞检测

一般而言,有两种我们想要在不同时间测试的不同情况。第一种,我们可能仅仅对两个模型是否碰撞了感兴趣,那么这一方法可在找到了一对三角形的重叠部分后终止。第二种,我们可能希望找出所有对重叠的三角形。第一个问题的解决叫做碰撞检测,第二个问题的解决叫做碰撞决定。在这里,给出了解决第一种方法的伪代码。第二种情况可以利用给出的代码做一些小改动得到,这在一会儿后会讨论到。

A和B是模型层次的两个节点,第一次调用的是模型的根节点。适用于访问合适结点的包围盒。回忆是结点A的孩子结点的集合,而则用于给定一个叶结点的三角形(在伪代码中,每个结点只对应一个三角形)。主要的想法是,当检测到重叠后,开启一个(更大的)包围盒并且递归的检测它的内容。

正如我们能在伪代码中看到的一样,代码中的一部分是能共用的,为了能够表达算法如何工作,它被表达成这样。有一些行需要特别需注意。1,2行考虑了两个结点都是叶结点的情况。3-10行则处理两个结点都是内部结点情况。Volume(A)>Volume(B)比较的结果是有着最大下降体积的结点。这样一个测试背后的想法是,在调用FindFirstHitCD(A,B)和FindFirstHitCD(B,A)后得到相同的树的遍历,所以遍历的结果是确定的。考虑到第一种碰撞检测有特殊的状态(提早结束,碰撞响应等),这一点是很重要的。也许更加重要的是这趋向于带来更好的性能,因为在每一步都先访问最大的盒子。另外一个想法是在下降的A和B间交替选择。这避免了体积计算,所以速度更快了。或者说,对于每个刚体而言,体积是可以提前计算的,但是这需要每个结点更多的内存。同样,注意对许多包围盒而言,实际的体积是不需要计算的,因为只需要计算“Volue order”就足够了。例如,对于球体而言,只要计算出半径就足够了。

为了找到碰撞的所有对三角形,伪代码可以这样修改。算法找到的三角形对存储在全局的链表L中,初始化为空。然后修改第2行:如果通过了测试,这个程序应当往L中加入一对三角形(而不是返回)。当递归结束后,所有的碰撞都能在L中找到。

代价函数

下面方程中的函数t,一开始被介绍为一个光线追踪加速算法中评价层次包围盒结构性能的框架。它也因此被用于评价碰撞检测算法性能,同时,它增加了最后一项,引入某些可能对性能有重大影响的新代价。这一估计的结果源于这样一个事实,如果模型正在进行刚体运动,那么它的包围盒以及它的部分或者全部层次都需要根据运动和包围盒的选择而重新计算。


 
        这里,参数代表:
        Nv : 包围盒重叠测试的个数
        Cv:包围盒重叠测试的代价
        Np:用于重叠测试的基元对对个数
        Cp : 检测两个基元是否有重叠的代价
        Nu : 根据模型运动更新的包围盒个数
        Cu :更新一个包围盒的代价
 
        创建一个更好的模型层分解可以导致更小的Nv,Np,Nu。创建决定两个包围盒或者三角形重叠是否有更小的Cv和Cp的方法。但是,这两个目标经常是矛盾的,因为改变包围盒类型以获得更快的重叠测试通常意味着我们得到了包的更松的包围盒。

过去用过的不同包围盒包括球体,轴向包围盒(AABB),方向包围盒(OBB),k-DOPs(离散方向多面体),扇形区,球壳(非常适合于Bezier面片),line swept spheres(LSSs),rectangle swept sphere(RSSs),以及QuOSPOs(它集合了OBBs和k-DOPs的优点)。球体是变换起来最快的,它的重叠测试同样也很快,但是它们的适应性很差。AABBs有更好的适应性以及更快的重叠测试,如果模型中有大量轴向分布的几何体的话,这会是一个很好的的选择(在大多数建筑物模型中)。OBBs有更好的适应性,但是它的重叠检测更慢。而k-DOPs的适应性则取决于参数k——k越高适应性越好,重叠检测和变换速度也就越慢。对于k-DOP树的大多数信息而言,读者们可以去看Klosowsk的文章。

显然还有更多参数可以微调,以得到好的性能,这就是OBB树章节重点要介绍的内容了。

OBB树

在这一部分,我们将会展现首次由Gottschalk提出的OBB树,这是一个给碰撞检测领域带来巨大影响的数据结构。
        在碰撞检测中,两个平面非常靠近并且几乎平行的情况下,OBBs树表现得非常好。这一类情况通常发生在公差分析(tolerance analysis)和虚拟原型(virtual prototyping)上。

包围盒的选择

正如OBB树算法的名字所示,它所使用的包围盒是方向包围盒,OBB。这一选择的一个原因是之前使用的AABB(轴向包围盒)和球体的适应性太差。也就是说,它们在包住几何体时会留下很多空隙。OBB则对其包围的模型几何体相比AABB或球体有更好的聚拢性。

另一个原因是Gottschalk发明了一种判断两个OBBs是否重叠的新方法。这一方法比以往的方法要快得多。这一测试的速度主要是因为OBB经过了变换,其中之一转换成了处在原点的AABB包围盒。实际上的变换要花费63次计算,OBB之间的测试可能会在15次轴向测试中的某一次提早终止。变换之后,第一次轴向测试的终止要花费17次计算,而最后一个轴则要花费180次计算。OBB/OBB的重叠测试在章节16.13.5中介绍。

根据17.3.3中的代价估计框架,之前的推断意味着OBBs的nv和np相比要更小。

Van den Bergen提议了一个加速两个OBBs重叠测试的简单技术:仅仅忽略最后的九个轴向测试,它们对应着与第一个OBB的某条边和第二个OBB的某条边垂直的方向。这一测试通常被称为SAT lite。几何上,这可以被看做是两个AABB/AABB的测试,其中第一个测试是在第一个OBB的坐标系统上进行的,而另一个是在另一个OBB的坐标系统上进行的。这在下图中有进一步阐释。简化的OBB/OBB测试(忽略了最后九个轴向测试)有时候将会认为两个不相交的OBBs是重叠的。在这个例子中,OBB树中的递归可能比需要的走的更深。之所以要使用这样扩展的递归,是因为我们发现最后九个轴向测试只找出了重叠的很小一部分。忽略这些测试最终的结果是平均性能得到了提升。Van den Berge的技术在一个叫做SOLID的碰撞检测包中得到了应用,它同样也能操纵可变形对象。

在左边是两个OBBs(A和B),我们对其进行OBB/OBB重叠测试,忽略最后九个轴的测试。如果从几何上解释,那么OBB/OBB重叠可以近似成两个AABB/AABB重叠测试。中间的图解释了B可以怎样由A坐标系统中的AABB包围盒围住。C和A重叠,所以这个测试继续执行到右图。在这里,A被B坐标系统中的AABB包围盒围住,B和D并不重叠。所以,测试终止。但是,在三维上,D和B也可能重叠,但是A和B不会因为剩余的轴向检测而重叠。在这样的例子中,A和B被错误的认为是重叠的。

分层构建

主要的数据结构是一个二分树(16.2给出了定义),它的每个内部结点都存着一个OBB,每个外部结点(叶结点)仅存储一个三角形。由Gottschalk发明的自顶向下构建分层的方法,是分开去寻找一个多边形集合的紧OBB包围盒,然后将其沿着OBB某个轴向分割,这也就把三角形分成了两组。对于每一组,计算出一个新的OBB。OBB的创建在16.3中讨论。
        我们计算完一个三角形集合的OBB后,包围盒以及三角形应当被分裂然后形成两个新的OBBs。Gottschalk使用的策略是选择包围盒所占据的更长的轴向,并且把它分为两个长度相同的部分。下图给出了这一过程的解释。一个包含包围盒中心点并且法线为包围盒最长轴的平面,被用于把三角形分为两个子集。被这个平面分割成两部分的三角形属于包含其质心的那一组。如果最长轴没有办法被分割(在极少的情况下,所有三角形的质心都处在分割平面上,或者所有质心都处在分割平面的同一侧),将会降序去尝试另一个轴向。

这张图显示了我们如何将几何体集合的OBB沿着其最长的轴向分解,也就是虚线标注的点。然后这个几何体被分解成两个字部分,每一部分都找到了一个新的OBB。将递归调用这个过程来创建OBB树。

对于每个子集而言,在16.3中介绍的矩阵方法被用于计算(子)OBBs。如果OBB选择了在中点处分裂,那么就获得了平衡树。
        因为计算凸包要花费O(nlogn)时间,而二叉树深度为O(logn),所以总的创建OBB树的时间复杂度为

操控刚体运动

在OBB树层次中,每个OBB,A,和一个刚体变换(一个旋转矩阵 R和一个平移向量t)矩阵Ma存储在一起。这个矩阵保存了OBB和其父母的相对朝向和位置。

现在,假设我们开始测试两个OBBs,A和B。A和B之间的重叠测试应当在其中一个OBBs的坐标系统完成。假定我们在A的坐标系统进行测试。在这种方式下,A是一个中心在原点的AABB包围盒(在它自己的坐标系统下)。接下来的想法是把B转换到A的坐标系统。这是利用下面给出的矩阵完成的,它首先将B转换到自己的位置和朝向(用矩阵Mb),然后再转换到A的坐标系统(使用A转换的逆)。回顾对于刚体变换而言,其倒置就是逆,所以不需要额外的计算:


 
        OBB/OBB的重叠测试将一个含有3X3旋转矩阵R和一个平移向量t的矩阵作为输入,它保存了B相对于A的朝向和位置,所以可按如下分解:


 
        现在,假设A和B有重叠,那么我们想要下降到A的孩子C。一个聪明的做法如下。我们选择在C的坐标系统进行测试。想法是把B转换到A的坐标系统(用  ),然后再转换到C的坐标空间(使用)。这是使用以下矩阵完成的,它将作为OBB/OBB重叠检测的输入:


 
        这一过程将递归地调用以测试所有的OBBs。

杂谈

检测两个层次树的FindFirstHitCD伪代码(第三部分),可以用于以上的算法。需要修改的地方是overlap()函数,它应当指向一个检测两个OBBs重叠的程序。

OBB树涉及到的所有算法可以使用一个免费软件包RAPID演示。

[图形学] 《Real-Time Rendering》碰撞检测(二)相关推荐

  1. 颜色 /About Color --图形学的B面(二)

    --图形学的B面(二) 本文谈论"颜色",是图形学的B面系列文章第二篇,这首先是一篇技术文章,和艺术无关,要深入探讨颜色背后的问题,颜色不是RGB,不是一个数字.本文要解决下面几个 ...

  2. [图形学] 《Real-Time Rendering》碰撞检测(三)

    目录 多重物体碰撞检测系统 广阶段的碰撞检测 Sweep-and-Prune 网格 总结 更多样的话题 时间临界的碰撞检测 距离查询 多重物体碰撞检测系统 考虑一个有弹簧和齿轮的旧式时钟,我们用一个计 ...

  3. [图形学] 《Real-Time Rendering》卡通渲染

    原文:<Real-Time Rendering,Third Version> Toon Shading章节 11.1 卡通着色 正如不同的字体能给文字带来不同的风格一样,不同的渲染风格也有 ...

  4. 虎书学习笔记4:图形学基础数学(隐式二维直线、隐式二次曲线、二维参数曲线、二维参数直线、二维参数圆)

    关于图形学的基础数学知识 基础数学 隐式二维直线 我们最熟悉的直线:斜截式 他的隐式方程为: 我们再函数y-mx-b=0两边同乘一个系数,将得到一摸一样的直线. 因为两个点觉得一条直线,所以必然满足: ...

  5. 《计算机图形学》学习笔记(二)

    图形显示设备 图形输出包括推行的显示和图形的绘制 图形显示指的是在屏幕上输出图形 图形绘制通常是指把图形画在纸上,也称硬拷贝,打印机和绘图仪是两种最常用的硬拷贝设备. 阴极射线管(CRT Cathod ...

  6. 计算机图形学笔记——第7章 二维几何变换 Python

    第7章 二维几何变换 应用于对象几何描述并改变它的位置.方向或大小的操作称为几何变换(geometric transformation). 几何变换有时也称为建模变换(modeling transfo ...

  7. 图形学书籍 Real-Time Rendering 3.4 可编程着色和 API 的演变(根据谷歌翻译修改)

    3.4 The Evolution of Programmable Shading and APIs 可编程着色和 API 的演变 The idea of a framework for progra ...

  8. 计算机图形学应用调研论文,计算机图形学的应用论文(2)

    计算机图形学的应用论文篇二 <分析计算机图形学的发展及应用> 摘要:经历了三十多年的发展,在科学计算可视化.自然景物仿真.计算机艺术.计算机制造.图形实时绘制.计算机动画以及计算机辅助设计 ...

  9. 三个基本原理和概念 - 计算机图形学、数据加密、数据挖掘

    一. 计算机图形学最基本原理 计算机屏幕由像素组成.一个像素点包括X和Y坐标.     高级语言有画基本图形的函数或语句,可以直接调用画图形.比如画线,画圆,画四方形.     但是最底层的编程接口, ...

最新文章

  1. oracle 查询天,Oracle查询_ 单表查询
  2. Linux云自动化运维第六课
  3. maven 打包jar_Maven一定要会的这几个知识!
  4. 分号是c语言中,问什么C程序里总是提示缺少分号;,而明明有分号?
  5. [C++11]forward完美转发
  6. 查看 Linux 系统版本(发行版本)信息的相关命令语句
  7. SQL入门语句之LIKE、GLOB和LIMIT
  8. c语言 prototype_(创建型模式)Prototype——原型模式
  9. 基于jQuery鼠标悬停上下滑动导航条
  10. Jupyter notebook基础教程(启动,汉化,操作)
  11. 【TP】TP如何向模板中的js传变量
  12. R初学者指南pdf 百度云盘
  13. deap dataset的不同分类模型的实现(2)-认识数据
  14. 银联在线php支付接口,PHP网站在线银联支付实现大额付款案例
  15. Unity 模拟投影器(Projector Simulator)
  16. 2021年计算机二级考试系统是哪个版本?
  17. ipad iphone开发_如何在iPhone或iPad上“不信任”计算机
  18. word2vec-google code
  19. 安卓熊猫视频压缩器v1.1.51高级版
  20. 大龄青年自学Java,如何找到第一份工作?

热门文章

  1. 百度搜索引擎优化(PHP自动推送连接到百度搜索引擎)代码
  2. python机器学习(二)——机器学习算法分类
  3. 【循环链表】数据结构——单向循环链表和双向循环链表操作笔记
  4. 【MongoDB数据库】MongoDB 命令入门初探
  5. 有趣的 CentOS 7 命令
  6. 犰狳空间extra关卡1-10 通关摘要
  7. 什么是POP3、SMTP及IMAP?
  8. 通过注册表获取Internet选项中代理服务器参数
  9. 三星NC10、ND10上网本Fedora11、Fedora12下屏幕亮度调节
  10. 【PS/PSD】182套国风烫金PSD素材合集