八叉树实现三角形网格和粒子

时间:2014-07-12 09:23:05

标签: c++ collision particles octree space-partitioning

我目前正在为CPU和GPU中的粒子模拟开发一个高效的计算引擎。我最近一直在八小时工作,我设法为太空中的粒子编写一个八叉树的工作版本,并有效地处理它们的碰撞。现在我必须在我的八叉树中插入三角形网格(STL对象),这样我才能处理粒子和对象三角形之间的碰撞。我很困惑如何以有效的方式将三角形插入到我已创建的八叉树中?请建议实现此目的的方法。如果这有帮助,我正在使用C ++。谢谢。

2 个答案:

答案 0 :(得分:2)

将三角形插入现有八叉树应该与创建新八叉树并将其插入其中不同。这里唯一关键的是确保您现有的八叉树覆盖一个3D空间,保证包含所有三角形。

除此之外,关于插入本身,基本上我建议实施两步插入,在第一步中你使用一些快速测试来查看某个三角形是否可能包含在某个立方体中,并且在第二阶段(如果第一个已经通过)你实际上做了一个正确的计算来看到这一点。

快速测试之一是得到三角形的边界框(从所有点的最小x,y,z到所有点的最大x,y,z)并将该框与其中的一个进行比较。八叉树(如果同一轴上的三角形框的两个坐标都不在八叉树框定义的范围内,并且都位于同一侧(下方或上方),那么它肯定在外面。

显然,一旦你发现了一个三角形和一个八叉树框之间的交集,你应该为它的所有子框重复这个测试。

算法中还有其他地方可以提高效率(例如按x,y,z排序框和三角形,然后进行只考虑相关框的检查),但这取决于你的等级希望优化。

答案 1 :(得分:1)

如果你的粒子是统一大小而你的三角形不是,那往往需要一种非常不同的数据结构。对于大小均匀的粒子,您可以将它们视为点,只需将一个粒子存储在树中的一个叶节点中作为空间中的单个点(如果它具有大的半径/大小,则无关紧要)粒子大小一致,因为你的搜索查询,只要它们按粒子的大小扩展,就会总是拿起它们的中心点。)

对于三角形,它们的大小可以变化很大,并且可以与8个子八分圆的多个相交。因此,您可以做我知道的几件事:

  1. 只需将指针/索引插入多个叶子中的三角形,并且只需要一些冗余,或者简单地复制所有叶子中的整个三角形数据(如果你不小心使用它,那么在内存中可能是爆炸性的)根据内容调整树的参数,但它可以使搜索更加缓存友好。)
  2. 拆分三角形,使其与两个或多个八分圆相交,成为两个或多个分割三角形。这对于构建/更新来说往往有点贵,但如果您以缓存友好的方式将三角形数据直接存储在树叶中,它可以快速进行查询。
  3. 使用松散的表示,如松散的八叉树。在这种情况下,您只需在插入时将三角形视为单个点。但是,您可以展开在插入过程中遍历的所有八叉树节点的AABB,以包含三角形。
  4. #1对于动态内容来说往往是不错的,只要你最小化构建树所涉及的内存使用和处理,并为八叉树设置一些理智的限制,例如最大深度,这样它就不会无限期地分裂

    #2对于静态内容往往非常好,并且往往非常适合快速搜索,因为它可以产生比#1更浅且更平衡的树,因为你没有存储重叠的数据在叶子里往往希望它们比理想情况下分裂更多。如果您的数据是静态的,那么您可能只需要在八叉树中直接存储一个副本,并且八叉树可以自由地修改所有希望提供最快搜索的数据。

    #3往往非常适合动态内容,因为它可以平衡构建/更新树和搜索树之间的开销。然而,松散的八叉树对搜索查询的性能有很大影响,因为以前对中心点进行简单检查以确定现在要遍历哪些八分区需要检查所有8个八分圆的AABB以确定哪些子节点在搜索过程中遍历。但是,它显着降低了构建和更新树的开销,使其在动态内容中得到很好的平衡,例如,网格在交互式实时环境中的每一帧都会变形。

    这些类型的问题可以帮助您准确地指定您的需求,例如您的网格是否是静态的,您是否需要快速更新/构建/搜索或平衡(您通常无法制作所有这三个事情超级快:一个超级快速通常意味着让另一个更慢)。

    例如,光线跟踪器经常使用非常适合极端静态内容的代表,因为它们通常可以花费一些额外的时间来构建结构,因为它们之后可能会执行十亿次光线/三角形交叉测试。光线跟踪器花费100毫秒来构建/更新其空间索引并不一定是一件大事,因为在生产质量上渲染完整场景可能需要几秒钟甚至几分钟或几小时。离线渲染标准100ms是微不足道的时间,按实时标准来说,这是一段史诗般的时间。另一方面,最快的搜索时间是如此,对于光线跟踪器来说非常重要,因此松散的八叉树通常是一个可怕的选择,并且大多数光线追踪者通常会想要将交叉测试所需的数据深度复制到叶子中以便它们不会#39; t需要零星的内存访问模式来访问存储在叶子中的数据。

    然而,物理引擎处理在实时上下文中移动的许多事物的碰撞检测将需要适合于动态内容的非常不同的表示。在完全交互式实时环境中处理静态和动态内容的广泛混合的游戏引擎可能会使用多种数据结构:每种结构都根据它们存储的内容类型进行定制。

    如果您的粒子确实是统一大小的,那么我建议使用不同的数据结构(例如,不同类型的八叉树)来存储三角形网格。如果您的粒子非常动态,而您的网格是相当静态的,则也是如此。在这种情况下,如果您要搜索粒子是否与网格或粒子碰撞,您可能首先检查存储针对三角形优化的网格的八叉树。如果您没有找到相交的三角形,则搜索另一个适合存储动态,均匀大小的粒子的八叉树,以检查粒子 - 粒子碰撞。您仍然可以将其抽象为看起来像单个数据结构的点,但理想情况下,您应该使用两种不同的实现。

    对于变换的网格,存储两个八叉树也是有用的:整个网格的外八叉树仅用于针对其AABB的粗略交叉测试,例如:然后,如果粗略交叉测试通过,则搜索每个网格存储的八叉树以找到哪个三角形相交。这允许您在网格变换时避免更新八叉树存储三角形(例如:旋转时)。