之前说到了很多空间索引结构,八叉树,bucket sorting,k-d tree:
今天就来说说另一类空间索引结构,BVH (多层包围盒树,Bounding Volume Hierarchies),这种算法与四叉树与八叉树、K-D树最大的一个区别就是:之前讲到的树状结构,是以空间本身为主进行划分,而BVH则是由空间中的物体本身为主题,递归的构造树状结构。
当代的物理引擎,就很多采用BVH的方法进行构建空间中的索引数据结构,原因就在于上述说的主要不同,如下图所示:
得到BVH的方法如下:
至此所有的物体都已经划归到了这个BVH数据结构中,那么如果现在有个物体想检查与哪个物体是否碰撞,就从同步红色节点开始搜索就好了:
所以大家可以看到这个碰撞检测从上到下的流程跟之前的八叉树、K-D tree是十分类似的,复杂度也为
这就是一个简单(最天真版本的BVH)的生成与搜索的全过程。
除了上述说的自底向上的生成方式(可以看到,我们是最先循环树的最底层),另外还有一种自顶向下的生成方式,其实原理也非常好理解,最简单的思路就是分别对不同的轴进行二分,比如先沿着x轴取个中位数,然后对左边的物体和右边的物体分别构建bounding box, 然后在对下一层再构建bounding box,直到停止条件为止 (一般就是只有单一物体)。
那么说完了比较简单的BVH的生成与搜索方法(BVH的优化的花样老多了,我也并不全知道),我们就来讨论一下,这玩意为啥在物理引擎中用的很多,相比于传统的八叉树、K-D tree等,其最大的优势就在于它的 ”以物体为主体,而不是以空间为主题“。以下是物理引擎中常见的场景
从中可以看到,在这种场景下,大多数物体是不动的,而那几个人,人的手,手里的刀则是无时无刻不在动的,这个时候呢为了快速进行碰撞检测,首先不可能不用任何空间索引而直接进行无脑全部搜索,而当用了空间索引,由于人时时在动,完全没有任何可预测性,就要动态的更新空间索引结构,那么BVH的优势就显示出来了,由于其是针对”物体的“,我们可以动态的更新物体的包围盒子,这个开销很小,然后再往上层更新上层节点的包围盒子,必要的时候再进行树旋转、合并和分裂等操作,所以这是一条”局部更新“的路线,大多数不动的东西根本不需要更新。而于此相比对于八叉树,k-d tree 等由于被划分的是”空间“,或者更严格来说是”有一些物体的空间“,物体 位置形状的改变,会造成整个树状索引发生改变(当然也有些优化方法),但总的来说在上述这种动态的场景中开销也是会大很多。
那么回到有限元,为啥有限元接触检测中BVH的高度没有物理、游戏引擎中这么高呢,原因在于大多数有限元接触分析研究的是变形体与变形体的接触,且两个物体每个单元每个节点都在变形,所以在大变形、大滑移的情况下,可能无论如何我们都得进行全局的空间索引重新构建,这个时候哪个构建的最快(相比BVH是局部更新快,全局都更新就未必快),可能才是最优的选择。