Loading

【空间加速结构】——四叉树

四叉树是一种对空间进行划分的数据结构。它将空间分为四个相等的部分,然后递归下去,达到一定深度或某种限定条件后停止分割。

如果一个元素与父节点不相交,那么它与子节点必然不会相交,那就不必与子节点进行相交运算了,从而达到加速的目的。四叉树可以用来加速视锥裁剪、相交检测。

那么给定一个场景,尝试来建立它的四叉树。

我们会面临几个问题。

  1. 物体是有包围体积的,它与节点的边界相交,应该如何处理?
  2. 物体在边界来回移动,如何处理?
  3. 建立四叉树的终止条件是什么?怎么做更好?

第一个问题,物体是有包围体积的,它与节点的边界相交,应该如何处理?

一般有两种解决办法:

  1. 所有与物体相交的叶子结点都存储该物体。
  2. 令非叶子结点能存储物体。

第1种方法的比较精确,但是问题在于大体积的物体会被非常多的子节点引用,管理麻烦,索引效率也比较低。

第2种方法比较常用,但是如果物体的包围盒与场景中心相交,那么即使再小的节点,也会被放到根节点中。而要解决这个问题,可以用松散四叉树。当划分空间时,将这个空间适当扩大,以容纳更多的物体,这样很多物体会被尽可能的子节点容纳,从而提高索引效率。

第二个问题,物体在边界来回移动,如何处理?

最简单的方法是,只要移动了就将它从四叉树中删掉,然后再重新添加即可,当然这不好。可以检查新位置与旧位置是否在同一个叶子结点的范围内,如果是就不需要做重新插入的操作。

在上面提到的松散四叉树的结构下,结点有内边界(inner boundary)和外边界(outer boundray)。

检查物体是否已越过之前的外边界,如果已越过再检查进入了哪个结点的内边界,就可以知道如何更新物体的节点了。松散四叉树由于外边界的存在,也减少了移动的物体需要更新节点的次数。

另外物体被从原节点删除时,它从在的节点已经没有其他物体了,是否要删除这个节点呢。如果当物体被删除时,同时立即删除节点时,可能会面临马上就需要重新创建这个节点的情况。可以设定一个时间,一段时间过后,仍无物体加入到这个节点中,那么就其删除。

第三个问题,建立四叉树的终止条件是什么?怎么做更好?

建立四叉树要考虑遍历、插入的时间消耗,以及内存空间的耗费。

最暴力的方法,建立满四叉树,对空间和遍历时间都有很高的浪费。所以动态的创建结点,如果物体被插入到四叉树中,没有合适的结点存放,创建新的节点。再加上树深度的限制(4~7比较合适),可以大大减少节点的数量。

当然还有优化的空间,在下面这种情况下,会有很多的叶子节点只存放了1个物体。可以给节点加一个容量的概念,当节点被插入的物体数量大于容量时,分裂这个节点,也就是创建子节点,将物体插入到合适的节点中。

其他

八叉树原理同四叉树是一致的,只不过需要拓展到三维空间,更适合有高低起伏的场景。

知乎上有提到更好的空间划分方法——VDB,待研究。

www.museth.org/Ken/Publica…

GitHub - AcademySoftwareFoundation/openvdb: OpenVDB - Sparse volume data structure and tools

posted @ 2022-03-01 00:06  silence394  阅读(0)  评论(0)    收藏  举报  来源