空间数据结构

空间数据结构我这个是项目中用来解决一些问题,包括在引擎中的场景管理!做了一个ppt来演讲,所以底下有的直接就用ppt的内容或者截图~
二维下使用四叉树、Kd-tree等等在三维下使用八叉树、bvh-tree、BSP-tree
BVH-tree在动态场景下使用(游戏使用的最多);Oc-tree八叉树是对于室外大场景来说的;BSP-tree是对于室内场景;
用途:场景管理、碰撞检测、LOD、光线追踪、 视椎体面剔除、几何加速;

KD-tree(以光追为例)

其每次将空间划分为两部分,且划分依次沿着x-axis,y-axis,z-axis,即如图中所示,第一次横着将2维空间分为上下,第二次再竖着将上下两个子空间分别划分为左右部分,依次递归划分,终止条件与八叉树类似,但是是以空间划分为依据;
在这里插入图片描述

循环以下步骤:
1 依次沿着x-axis,y-axis,z-axis划分,使得空间被划分的更加平衡
2 划分的位置由空间中三角面的分布决定,具体细节不展开
3 叶子节点存储对应空间的所有物体或三角面信息,中间节点仅存储指针指向两个子空间
4 当划分空间太小或是子空间内只有少量三角形则停止划分
区别:直接对空间进行划分,都是二分空间!比如先左右划分当前场景,再对子场景进行上下的划分

优点:
利用KD-Tree的结构来构建AABB的好处是倘若光线与哪一部分空间不相交,那么则可以省略该部分空间所有子空间的判断过程,在原始的纯粹的AABB之上更进一步提升了加速效率。
缺点:
缺点是判断包围盒与三角面的是否相交较难,因此划分的过程不是那么想象的简单,其次同一个三角面可能被不同的包围盒同时占有,这两个不同包围盒内的叶节点会同时存储这一个三角形面
近十年来 用的比较少;

层次包围盒树 (Bounding Volume Hierarchy Based On Tree)

不再以空间作为划分依据,而是从对象的角度考虑,即三角形面(主要是应用于动态场景)

层次包围盒树(BVH树)是一棵多叉树,用来存储包围盒形状。它的根节点代表一个最大的包围盒,其多个子节点则代表多个子包围盒。此外为了统一化层次包围盒树的形状,它只能存储同一种包围盒形状。 算法核心大概:形状的位移/旋转/伸缩更新对应的叶节点,然后一级一级更新上面的节点,使它们的包围体包住子节点, 构造时间复杂度只有O(NlogN)。
在这里插入图片描述

区别:利用了Bounding box(AABB)从物体来开始划分

优点:现代用的最多,主要是对于动态物体很多的场景;
缺点:包围盒的重叠问题!

一、轴向划分

轴向划分是 BVH 树中最常见的划分方式之一。通常沿着三个坐标轴(X、Y、Z 轴)进行划分。

  1. 选择轴:可以依次循环选择 X、Y、Z 轴,或者根据场景的特点选择具有最大扩展范围的轴进行划分。例如,如果场景中的物体在 X 轴方向上分布较为分散,那么可以优先选择 X 轴进行划分。
  2. 确定划分点
    • 选择物体包围盒的中心作为划分点,将空间分为两部分, 但对于不均匀分布的物体可能效果不佳。
    • 也可以通过计算所有物体在该轴上的中位数来确定划分点,使得划分后的两个子空间中的物体数量尽量接近。这样可以平衡树的深度,提高查询效率。当然也就使得树形结构建立的更加平衡,深度更小,平均搜索次数更少,提高了效率,这些都是数据结构的知识,相信大家掌握的都不错,就不多赘述了(重复此过程至叶子节点只有一个包围球)。
      二、对象大小划分
      根据物体的大小进行划分。如果场景中有大小差异较大的物体,可以将较小的物体划分到一起,较大的物体划分到另一起。
  3. 设定大小阈值:确定一个大小阈值,例如物体包围盒的体积或边长。
  4. 划分物体:将物体分为小于阈值和大于等于阈值的两组。对于较小的物体组,可以采用更紧密的划分方式,以减少包围体的冗余;对于较大的物体组,可以采用更宽松的划分方式,以避免过多的细分导致树的深度过大。

四叉树与八叉树:

二维使用四叉树、
在这里插入图片描述
三维是使用的八叉树(室外大场景)为了防止满树,优化需要线性八叉树(tree本质上就是数组)
在这里插入图片描述
比如子区域内的空间对象数量小于某个阈值、子区域的尺寸达到最小允许尺寸,那么子区域会继续被细分,如此递归下去,直到每个子区域都满足终止条件为止;也可以如下
递归分割立方体

  • F: 子立方体被场景内容填充满内容标记为F(full)该子立方体不再被分割;

  • E:子立方体没有场景内容标记为E(empty)该子立方体不再被分割;

  • 叶子节点是F或E;(缺点)

八叉树中的节点分为叶节点和非叶节点。叶节点用于存储实际的空间对象或者表示该区域内空间对象的相关信息(比如是否存在空间对象、空间对象的某些属性等)叶子节点是F或E;非叶节点则主要用于组织和管理子节点,起到空间划分和索引的作用。

松散四叉树/八叉树:减少边界问题

解决四叉树/八叉树一个问题,物体有可能在边界处来回(即在A象限也在B象限),从而导致物体总是在切换节点,从而不得不断更新四叉树/八叉树。除此之外较小的物体可能因为其特殊位置被存储到一个具有非常大的包围盒体积的八叉树节点中。

在《Game Programming
Gems》中该问题被描述为层次划分过程中产生的“粘性(Sticky)”区域,较小的物体却保持在树的较高层次,降低了划分的效率

在这里插入图片描述

而松散四叉树/八叉树正是解决这种边界问题的一种方式,首先它定义一个节点有入口边界(inner boundary),出口边界(outerboundary)。
那么如何判定一个物体现在在哪个节点呢?

  1. 首先它定义一个节点有入口边界(inner boundary),出口边界(outerboundary)。
  2. 判定一个物体现在在哪个节点
  3. 若物体还没添加进四叉树/八叉树,则检测现在位于哪个节点的入口边界内;
  4. 若物体先前已经存在于某个节点,则先检测现在是否越出该节点的出口边界,若越出再检测位于哪个节点的入口边界内。

在非松散的四叉树/八叉树中,入口边界和出口边界是一样的。而松散四叉树/八叉树的松散,是指出口边界比入口边界要稍微宽些(各节点的出口边界也会发生部分重叠,松散比较符合这种描述),从而使节点不容易越过出口边界,减少了物体切换节点的次数。
随之而来一个问题就是,如何定义出口边界的长度。因为太短会退化成正常四叉树/八叉树,太长又可能会导致节点存储冗余的物体。而在一篇关于松散四叉树/八叉树的论文里,实验表明出口边界长度为入口边界2倍时可以表现得很好。

线性八叉树:

存储在一个线性数组中,数组的每个元素对应一个八叉树节点。节点的存储顺序按照某种特定的遍历顺序(如深度优先遍历或广度优先遍历)确定。
优点:节省存储空间 快速访问和操作,避免指数级的爆炸 。
缺点:添加或删除一个节点时,会导致数组中很多元素需要移动位置。这会带来较高的时间开销,特别是当场景中的物体频繁变动时,这种更新操作可能会严重影响性能!

编码: 对于八叉树中的每个节点(即子立方体),根据其在空间中的位置进行八进制编码,使得每个编码唯一地对应一个特定的空间区域。常用的有 Morton编码求矩阵四叉树的四进制和十进制Morton码

在这里插入图片描述

BSP树(Binary Space Partitioning Tree):二叉空间分割

在游戏工业算是老功臣了,第一次被应用用是在1993年的商业游戏《DOOM》上,可是随时渲染硬件的进步,基于BSP树的渲染慢慢淘汰。但是即使在今天,BSP仍是在其他分支(引擎编辑器)不可或缺的一个重要数据结构。
(用在室内场景)用空间超平面,递归的将空间分割为凸多面体,用二叉树表示被分割的的空间(AVL树),场景中的平面都有前平面与后平面(平面法向量的为前平面)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值