Bounding Volumes
包围盒:用一个简单形状把物体包围起来,如果物体连包围盒都无法碰撞,一定无法碰撞包围盒内的物体
将长方体理解成三个不同对面形成的交集,一定是在x,y,z轴上的范围。没有旋转
Ray Intersection with Axis-Aligned Box
光线和包围盒求交
给定任何一根光线,可以求出光线何时和无限大的两个面有交点
之后看水平的对面,求两个面的交点
即对任何一个对面,可以求出进入的时间和出去的时间。
求交即可求出,光线何时进入盒子,何时出去盒子
对于3维空间,有3组对面,各计算一次光线进入对面的最小,最大时间·。求出最大的进入时间和最小的离开时间。如果进入时间小于离开时间,说明这段时间光线在盒子里
光线是射线不是直线,如果光线离开盒子时间小于0,说明盒子是在光线背后
当离开的时间是正的,进入盒子的时间是负的,说明光线起点在盒子里
当且仅当进入时间小于离开时间,且离开时间大于0,则光线与包围盒有交点
之所以用横平竖直的包围盒,因为光线与和xyz轴垂直的面求交比较方便
如上图,当对面与x轴垂直时,可以直接求光线在x轴方向上的传播
Uniform Spatial Partitions (Grids)
做光线追踪前的预处理
先找出一个场景,把场景的包围盒找出
把盒子分成一堆格子
判定哪些格子里可能有物体,将与物体表面相交的格子标记起来
做完预处理后可以开始进行光线追踪。
这里认为光线和格子求交是非常快的,和实际物体求交是非常慢的。
可以找到光线走的过程中相交的格子,如果格子中有物体,则光线可能与物体相交
只需要做若干次光线与格子的求交,来避免与场景所有物体进行求交
光线会打到哪个格子,最简单的思路可以是类似光栅化一条线段
极端的情况,将场景划分成1x1的格子,则没有加速
另一个极端是格子太密,则效率太低
启发式的算法:格子的数量应该是一个常数(27)乘以物体的数量
对于场景里各个地方都有几何物体,分布较均匀的情况下格子的效果比较好
当场景中物体分布很不均匀,有很多空的情况下,不适合格子的方式
Spatial Partitions/空间划分
八叉树:(2维空间下是四叉树),把空间切成四块,再把子块切成四块,知道其中有三块不和任何物体相交,则不在继续切。或者一块里有足够少数量的物体
kd树:和八叉树几乎一样,只不过每次会找一个轴,沿轴划分,保持了二叉树的性质KD-Tree
BSP树:对空间二分,每次选一个方向,把节点砍开,与kd树的区别是不是横平竖直的砍开。在维度高时,越来越不好计算
只需要在叶子节点实际存储和这些格子相交的几何形体
按x,y,z依次划分,选取划分位置,循环子节点
场景有一光线
判断和a是否有交点,有交点说明需要考虑是否和子节点有交点
如果有交点的是叶子节点,则和叶子节点里的所有物体求交
两个子节点都要判断,可能都有交点,所以B也判断求交
依次查询,直到求交到所有相交的叶子节点。类似二分查找
很难判断这个物体和包围盒是否相交,即格子和哪些物体相交。对于kd-tree,有个明确的问题。很难判断一个三角形和立方体有交集,如当一个三角形是插进这个盒子时,这个三角形的三个顶点都不在盒子里,但是和盒子相交。
近十年逐渐很少使用kd树来处理,就因为很难判断一个三角形和AABB是否有交点。另外如上图3,4,5都存储了一个物体。但是人们希望一个物体只在一个叶子节点里,所以kd-tree并不直观。
Object Partitions & Bounding Volume Hierarchy (BVH)
不从空间划分,通过物体来划分,这张划分形成的结构称为BVH
把一个盒子的所有三角形组织成两部分,再分别重新求包围盒
递归划分子节点
直到叶子节点有足够少的物体
kd-tree是直接把空间两份,bvh是把物体分成两堆,再重新求包围盒。
一个物体只可能在一个盒子里。
但bvh对空间的划分,并没有严格划分开,即不同的Bounding box有可能相交
选择维度:可以,x,y,z循环。也可以每次沿着最长的轴划分
排序,取中间位置物体划分。保证树接近平衡。
把所有的三角形取重心,通过重心进行排序。
如果只是找中位数的话,其实不需要排序,排序复杂度是 n log n n{\log}n nlogn。
给n个无序的数,找第i大的数,可以在O(n)时间内解决,称为快速选择算法,只对划分两边的某一边进行操作
中间节点只存包围盒与子节点指针,叶子节点存储实际物体
求交,类似kd-tree
总结:kd-tree划分的是空间,空间与空间之间不会有交集,但是物体可能在两个空间。bvh划分的是物体,包围盒间可能有相交,不需要处理物体和包围盒是否相交。