上次说到了 接触基础知识:从二分到四叉树与八叉树
说到了四叉树、八叉树与二分的关系,其实呢就是高维上的均匀二分法,那么其实在此之上还有一种变形,那就是K-D tree。
K-D tree的问题其实主要是为了解决以下的问题:假设蓝框框是需要划分的几何空间,为了快速搜索,假定我们待检测的几何或者网格在一个维度上分布很广,而在另外一个维度上基本空间位置没啥变化,那么传统的四叉树与八叉树就会造成一定的问题。比如看下边这个图,虚线将空间划分为4等分(典型的2D空间中的四叉树),那么左边2个小三角型分别横跨左边上下两个,右边的两个也是横跨右边上下两个,这个时候如果有个接触检测的物体进入这些盒子都需要进行接触检测,显然不是我们想要的。
那么我们来看看改进的K-d tree是咋做的呢,K-d tree 顾名思义,他的意思就是 的树结构, 为空间维度,对于2D来说, , 对于3D来说, ,其实也是在各个维度上进行二分,这里乍一看,跟上述四叉树八叉树也没啥区别,但这里他有两个比较重要的特点(起码我认为重要):
一般来说在三维中,按x→y→z→x循环选择分割维度,然后可以选择图形在该维度上的中位数作为分割点,确保树平衡,而且也并不一定每个维度都分割,比如像上述的结构,我们可以采用下边的方法
这样我们进行x方向的分割,并略过y方向的分割,因为如果像上述四叉树一样也进行y方向的分割无非是让格子变得更多,且每个格子里面物体的数量又不会减少(如上述四叉树),增加了存储又没带来啥好处。
所以这里可以看到K-d tree 提供一种比传统四叉、八叉树更为灵活的方式,可以分别在各个维度上剖分,可以认为是四叉树八叉树的改进型,不过编码方面会稍微麻烦一点,下一次我会结合编码直接来说一下,然后大家怎么选用看自己的选择。
另外,K-d tree还有一个大好处,因为他并不是对空间的均匀剖分,所以对于空间分布不均匀的情况也会效果更好一点,下图这个分布很不均匀的情况
用左边的四叉树,四个格子分别的单元数量(按照但凡有部分在就算属于这个格子的原则):
换成K-d tree 后:
可以看到存储的数量减少了很多,更重要的是后续在格子中做局部的接触检测的数量会减少,提高计算效率。
最后总结一下:K-d tree和四叉、八叉树在查询效率和构建复杂度方面基本一致,但是K-d tree 可能更省内存,各个区域的划分可能更均衡,虽然理论上并不会改变计算复杂度的级别,但是实操起来对于一大堆数据的情况(特别是接触、动态的、不均匀的),往往能效率更高一些。