基于稀疏八叉树的并行刚体碰撞检测方法及装置

文档序号:30955661发布日期:2022-07-30 09:49阅读:196来源:国知局
基于稀疏八叉树的并行刚体碰撞检测方法及装置

1.本发明属于计算机图形学与人机交互领域,具体涉及一种基于稀疏八叉树的并行刚体碰撞检测方法及装置。


背景技术:

2.八叉树是一种在计算机仿真领域非常常见的数据结构,广泛应用于碰撞检测、光线跟踪、以及三维场景的简化等领域。随着人们对仿真真实感和帧率需求的提升,越来越多的仿真算法不在满足于cpu的计算,开始使用gpu并行加速求解。然而gpu虽然并行的计算速度比较快,但是目前的gpu设计架构还不支持递归算法和动态的内存分配,导致某些gpu算法与cpu算法实现过程有较大的差别。许多复杂的数据结构和算法不适用于使用gpu实现。传统的八叉树采用自顶向下的方式进行构建,这种方式难以使用gpu进行并行的构建。ferrando通过使用结合cpu和gpu的不同的优势来创建八叉树的算法[ferrandon,m.a.gos
á
lvez,j.cerd
á
,et al.octree-based,gpu implementation of a continuous cellular automaton for the simulation of complex,evolving surfaces[j].computer physics communications,2011,182(3):628-640.]。八叉树的结构由cpu来创建,节点与节点之间的数据通过gpu来计算和传输。这种方法在一定程度上弥补了cpu和gpu各自的短板,但是也造成了cpu和gpu之间通信的开销。熊等人提出一种基于混合八叉树的动态对象碰撞检测算法[熊心一,姚宇.基于混合八叉树的动态对象碰撞检测算法[j].计算机应用,2019(a01):96-99.]。该算法结合了静态八叉树和动态八叉树的特点,在一定程度上降低了空间消耗,但该算法无法应用于实时计算,效率有待提高。


技术实现要素:

[0003]
本发明主要针对传统的刚体碰撞检测算法效率低的问题,提出一种基于稀疏八叉树的并行刚体碰撞检测方法及装置,其通过使用z空间填充曲线(z-sfc)和索引,进而构建自底向上的八叉树,从而极大的降低了碰撞检测的复杂度,同时该方法适合使用gpu进行并行求解,使得大规模刚体碰撞实时检测和计算成为可能。
[0004]
具体来说,本发明的技术方案如下:
[0005]
一种基于稀疏八叉树的并行刚体碰撞检测方法,其步骤包括:
[0006]
1)根据待碰撞检测刚体构建包围盒树,依据包围盒树的根节点生成碰撞区域,并对碰撞区域进行划分,对获取的各小单元空间进行编码,生成各小单元空间的索引;
[0007]
2)依据待碰撞检测刚体的重心及各小单元空间的索引,构建压缩八叉树的叶子节点;
[0008]
3)将两个相邻叶子节点的最小公共父节点作为内部节点,对不同层的内部节点进行并行排序,生成压缩八叉树的后序遍历,并结合内部节点与压缩八叉树的后序遍历,生成压缩八叉树;
[0009]
4)通过计算压缩八叉树中每个节点与其父节点之间的深度差,获取中间节点,生
成完整八叉树;
[0010]
5)从完整八叉树的叶子节点开始自底向上查询重叠区域,找到发生碰撞的叶子节点对。
[0011]
进一步地,所述包围盒树包括:轴平行包围盒树和有向包围盒树。
[0012]
进一步地,通过以下步骤构建包围盒树:
[0013]
1)对各待碰撞检测刚体pi的轮廓进行重构,i为待碰撞检测刚体的序号;
[0014]
2)把待碰撞检测刚体p1作为包围盒树的根节点,将其它的待碰撞检测刚体pi作为包围盒树的一节点;
[0015]
3)判断待碰撞检测刚体p1与其它的待碰撞检测刚体pi所在的区域是否存在交集;
[0016]
4)若有交集且其它的待碰撞检测刚体pi与待碰撞检测刚体p1的子集有交集,则将其它的待碰撞检测刚体pi的相应节点加入到与待碰撞检测刚体p1的相应节点的子集最小的公共子节点之后;若没有交集,则根据待碰撞检测刚体p1与其它的待碰撞检测刚体pi生成一公共区域,并生成公共节点。
[0017]
进一步地,对碰撞区域进行划分的方法包括:z空间填充曲线。
[0018]
进一步地,编码的方法包括:莫顿码。
[0019]
进一步地,通过以下步骤构建压缩八叉树的叶子节点:
[0020]
1)获取待碰撞检测刚体的重心,得到叶子节点的坐标;
[0021]
2)依据各小单元空间的索引,将叶子节点的坐标表示为索引形式;
[0022]
3)将索引形式的叶子节点坐标保存在一长度为2n-1的数组a中,其中n为待碰撞检测刚体pi的数量;
[0023]
4)根据索引形式的叶子节点,对数组a中的n个元素进行排序,构建压缩八叉树的叶子节点。
[0024]
进一步地,通过以下步骤得到压缩八叉树的后序遍历:
[0025]
1)分配n-1个gpu线程;
[0026]
2)对于由数组a前半部分中的两个相邻叶子节点a[i]与a[i+1]生成的内部节点,存储在数组a[n+i]中;
[0027]
3)根据各小单元空间的索引,对不同层的内部节点进行并行排序,并删除数组a后半部分中的重复项;对于没有相同索引的每两个相邻内部节点,并行地从当前节点开始遍历数组a的后半部分,并删除重复项;
[0028]
4)根据各小单元空间的索引对数组a进行并行排序,得到压缩八叉树的后序遍历。
[0029]
进一步地,通过以下步骤生成压缩八叉树:
[0030]
1)分配两倍于数组a大小的数组b,并将数组a中的数据复制到数组b中;
[0031]
2)分配p+q-1个gpu线程,其中p为叶子节点的数量,q为内部节点的数量;
[0032]
3)对于数组b前半部中的每两个相邻叶子节点b[i]与b[i+1],并行生成内部节点,并将存储在b[n+i]中;
[0033]
4)根据小单元空间的索引对生成结果进行并行排序;
[0034]
5)对于具有相同索引且至少其中一个不是副本的节点,建立内部节点父子关系,生成压缩八叉树。
[0035]
进一步地,通过以下步骤生成完整八叉树:
[0036]
1)分配不小于数组a长度的线程;
[0037]
2)计算每个节点与其父节点的深度差并累加,以获取插入内部节点所需的内存总数;
[0038]
3)并行计算每个节点与其父节点之间的深度差,且当深度差大于设定阈值时,并行的在每个节点与其父节点之间插入中间节点,以生成完整八叉树。
[0039]
一种存储介质,所述存储介质中存储有计算机程序,其中,所述计算机程序被设置为运行时执行上述所述的方法。
[0040]
一种电子装置,包括存储器和处理器,所述存储器中存储有计算机程序,所述处理器被设置为运行所述计算机以执行上述所述的方法。
[0041]
与现有技术相比,本发明具有如下的优点:
[0042]
(1)本发明提出一种基于稀疏八叉树的并行刚体碰撞检测方法,使用z空间填充曲线(z-sfc)将碰撞区域进行有效的线性化,从而极大的降低了计算开销;
[0043]
(2)本发明中每一个步骤都具有高度并行性,因而适用于现有的gpu架构,可以利用硬件加速,实现对大规模刚体碰撞的实时检测和计算;
[0044]
(3)本发明与传统的单线程cpu进行递归的八叉树构建相比,在大规模的碰撞场景情况下,效率可提高两个数量级。
附图说明
[0045]
图1为方法的流程图。
[0046]
图2a为刚体1-9空间位置图。
[0047]
图2b为构建的aabb树图。
[0048]
图3a为二维空间的z空间填充曲线(z-sfc)划分示意图。
[0049]
图3b为对z空间填充曲线(z-sfc)划分的结果进行标记示意图。
[0050]
图4为刚体1-9空间划分示意图。
[0051]
图5为z空间填充曲线索引示意图。
[0052]
图6为不同层级的z空间填充曲线示意图。
[0053]
图7为基于gpu的并行八叉树的构建示意图。
[0054]
图8为内部节点的父子关系示意图。
[0055]
图9为生成的压缩八叉树示意图。
[0056]
图10为压缩八叉树生成完整的八叉树示意图。
[0057]
图11为完整的八叉树结构示意图。
[0058]
图12为八叉树自底向上并行碰撞检测示意图。
[0059]
图13为碰撞区域细粒度检测示意图。
具体实施方式
[0060]
为使本发明的上述目的、特征和优点能够更加明显易懂,下面通过具体实现和附图对本发明做详细说明,但不构成对本发明的限制。
[0061]
本发明方法的硬件平台采用了型号为intel i7-8700的cpu,主频为3.2ghz,nvidia geforce gtx 1080ti显卡,显存8gb。系统程序采用c++编写,其中对于并行计算部
分采用了cuda语言进行加速,并借助microsoft visual studio 2017对程序进行编译执行,开发过程中采用了opengl、freeglut等开源库。
[0062]
本发明方法的流程图如图1所示,整个流程主要分为五部分。首先,对可能产生碰撞的n个刚体构建包围盒树(包括:aabb树(轴平行包围盒树,aixe align bounding box tree)和obb树(有向包围盒树),下述将以aabb树为例),将aabb树的根节点对应的区域,作为的碰撞区域;然后,使用z空间填充曲线(z-sfc)对碰撞区域进行划分,生成单元空间,并使用morton码(莫顿码)对单元空间进行编码,生成z空间填充曲线(z-sfc)索引,以便后续构建内部节点的邻接关系;接着,根据生成的z空间填充曲线(z-sfc)索引自底向上、并行的构建压缩八叉树;其次,对构建出来的压缩八叉树进一步并行的恢复成完整的八叉树结构;最后,根据完整的八叉树自底向上的进行并行碰撞检测。接下来我们将详细介绍每一个步骤的具体实现方案。
[0063]
1、构建aabb树。aabb树中每个子节点也是aabb树的结构,它只需要log(n)的时间复杂度就能完成节点的搜索过程。假设我们要检测刚体1-9的碰撞。根据刚体1-9的轮廓生成aabb包围盒。接下来通过执行以下操作来构建aabb树(如图2a与图2b所示):
[0064]
(a)把刚体1作为aabb树的根节点;
[0065]
(b)把刚体2和刚体1作比较,判断刚体2与刚体1所在的区域有没有交集。如果有交集则继续判断刚体2是否与刚体1的子集有交集,将其加入到与节点1有公共交集的子集的最小的公共子节点之后。如果刚体2与刚体1没有交集,则根据刚体1和刚体2的区域重新生成一个公共区域,作为节点1和节点2的公共节点;
[0066]
(c)重复步骤b),直达把所有的节点都加入到aabb树中,并将aabb树的根节点对应的区域,作为的碰撞区域。
[0067]
2、构建z空间填充曲线(z-sfc)和索引。z空间填充曲线(z-sfc)技术易于实现,并行化高,可用于将二维或三维空间中的区域进行有效的线性化。假设在d维空间中,将空间的每个维度均匀的分成k分,则会产生2
dk
个相等的非重叠的小空间单元。例如使用z空间填充曲线(z-sfc)对二维正方形区域进行划分,结果如图3a所示;根据图3a划分的结果按顺序进行标记,结果如图3b所示:
[0068]
例如将步骤1中的刚体1-9进行空间划分之后可得到图4结果:
[0069]
通常将划分的结果左下角的小单元空间设置为z空间填充曲线(z-sfc)的起点,并对区域进行morton码编码。在二维空间中,假设存在刚体p的重心位置坐标为(x,y),则将该坐标作为叶子节点的坐标。经过z空间填充曲线(z-sfc)划分之后,该点所属的单元将为对于刚体9横跨多个区域的需要进行去重操作,此时刚体9的z空间填充曲线索引设置为数值最小的区域即11110000,并保存这几个区域的信息。例如对图3a所示的二维空间创建z空间填充曲线索引如图5所示。
[0070]
根据z空间填充曲线(z-sfc)索引,我们可以创建不同层级的z空间填充曲线(z-sfc),如图6所示。
[0071]
3、基于gpu的并行压缩八叉树的构建。不同于cpu的八叉树构建,基于gpu的并行八叉树的构建是自底向上构建的。根据叶子节点所在的位置,反向生成内部节点,进而确定内部节点的关系,从而确定树的结构。自底向上生成树的过程适用于gpu并行计算。具体的实
施过程如图7所示:
[0072]
(1).构建叶子节点
[0073]
(a)将待检测的刚体1-9作为输入点,使用长度为2n-1(n表示刚体的数量)的数组a保存这9个输入点作为叶子节点。
[0074]
(b)根据叶子节点的坐标生成z空间填充曲线(z-sfc)索引。
[0075]
(c)根据叶子节点的z空间填充曲线(z-sfc)索引,并行对数组a中的9个元素进行排序。
[0076]
(2).生成内部节点和八叉树的后序遍历:对每个相邻的叶子,使用z空间填充曲线(z-sfc)索引中的公共位并行的找出最小公共父节点(lca)。例如,相邻叶子节点1和节点2的z空间填充曲线(z-sfc)索引分别为11000001和11000010,由此可得到节点1和节点2的最小公共父节点为11000000。
[0077]
(a)分配n-1个gpu线程。
[0078]
(b)对于数组a中的每两个相邻叶子(例如数组a[i]和a[i+1]),并行生成最小公共父节点,其最小公共节点的z空间填充曲线索引为叶子节点a[i]和a[i+1]的z空间填充曲线索引的最大公共部分,并将其值存储在a[n+i]中。
[0079]
(c)根据公共节点的z空间填充曲线索引,对不同层的内部节点进行并行排序。如果元素l1包含在元素l2中,则将l2元素置于l1元素之前;否则,将l1元素置于l2元素之前。图7中的(c)显示了排序后的内部节点,其中可能会生成重复项(n2和n3)。
[0080]
(d)在数组a的后半部分中,删除重复项。
[0081]
(e)对于没有相同z空间填充曲线(z-sfc)索引的两个相邻内部节点,并行地从当前节点开始遍历数组a的后半部分,删除它们重复的项。根据z空间填充曲线(z-sfc)索引对数组a进行并行排序,进而可以得到压缩八叉树的后序遍历。
[0082]
(3).生成压缩八叉树。我们可以注意到数组a的末尾可能会有一些空元素。这是无法避免的,因为cuda不支持动态内存分配和释放,因此必须在编译时就创建大小为2n-1的数组。然而仅仅得到八叉树的后续遍历还无法确定树的结构。图8中的(a)所示节点a和节点b属于同级的情况,因此它们的公共的父节点为c;图8中的(b)所示节点b是节点n的子节点,与节点a是相邻节点。图8中的(c)所示节点b是节点a的父节点。
[0083]
为了进一步确定八叉树的内部结构,执行以下步骤:
[0084]
(a)分配两倍大小的叶子和内部节点数的数组b(最多4n-2)。将数组a复制到数组b中。
[0085]
(b)分配(叶子节点数+内部节点数-1)个gpu线程。
[0086]
(c)对于数组b的前半部分中的每两个相邻节点,根据z空间填充曲线(z-sfc)索引并行的生成最小公共父节点。例如对于数组b中的每两个相邻叶子b[i]和b[i+1],并行生成内部节点,并将其存储在b[n+i]中,结果如图7中的(f)所示。
[0087]
(d)根据z空间填充曲线(z-sfc)索引对生成的结果进行并行排序,将所有的内部节点和它们的副本将归并到一起,结果如图7中的(g)所示。
[0088]
(e)对于具有相同z空间填充曲线(z-sfc)索引并且至少其中一个不是副本的节点,建立内部节点的父子关系(图7中的(h)和图7中的(i))。最终生成的压缩八叉树如图9所示:
[0089]
4.从压缩八叉树中恢复完整的八叉树。如图9所示的两个相邻的节点n4和节点3,其中节点3是节点n4的子节点。通过z空间填充曲线(z-sfc)索引来计算两个节点之间的深度差。例如节点n4和节点3的z空间填充曲线(z-sfc)索引分别为11000000和11001101,则深度差为2(节点n4处于深度1,节点3处于深度3,假设根深度为0)。这种差异表明压缩八叉树中缺少节点n4和节点3之间的中间节点,如图10所示。
[0090]
为了生成完整的八叉树结构执行:
[0091]
(a)分配大小等于数组a长度的线程,即(叶子数+内部节点数)。
[0092]
(b)计算每个节点与其父节点的深度差并累加,以获取插入内部节点所需的内存总数(由于gpu上不能进行动态的分配内存)。
[0093]
(c)根据每个节点与其父节点之间的深度差添加新的节点。当深度差大于1时,并行的在其中间插入新的节点。如图11所示,在节点n4和节点3之间插入了一个内部节点ch1,以获得完整八叉树结构。
[0094]
5.使用八叉树结构自底向上的对刚体进行并行的碰撞检测。如图12所示,从叶子节点开始自底向上进行检测,当发现碰撞点时进一步进行细粒度检测,直到找到发生碰撞的叶子节点对。
[0095]
(a)假设刚体2和刚体3发生了碰撞。针对待碰撞检测刚体,计算刚体所有八叉树层数及对应叶子节点,利用步骤4中八叉树自底向上查询所有重叠区域对应刚体的aabb包围盒。
[0096]
(b)如果找到碰撞包围盒,针对上述步骤(a)中得到的aabb包围盒进一步对刚体2和刚体3的边界进行精确的碰撞检测,结果如图13所示。
[0097]
以上实施方示例仅用以说明本发明的技术方案而非对其进行限制,本领域的普通技术人员可以对本发明的技术方案进行修改或者等同替换,而不脱离本发明的精神和范围,本发明的保护范围应以权利要求所述为准。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1