【问题标题】:Should an octree be rebuilt every frame?是否应该每帧都重建一个八叉树?
【发布时间】:2011-05-18 12:06:33
【问题描述】:

当在游戏中使用octree 进行碰撞检测时,是否应该每帧都重建树,或者是否有更好的方法假设一半对象在一帧中移动?

【问题讨论】:

    标签: c++ algorithm


    【解决方案1】:

    如果您的场景中有大量静态几何体,请考虑构建单独的八叉树。您还可以通过使用更复杂的叶节点来区分静态和非静态几何体来表达相同的想法。

    底线:只再生你必须做的。

    【讨论】:

      【解决方案2】:

      如果场景每帧都发生变化,那么你必须重做树。

      【讨论】:

      • 如果场景随着每一帧的变化而变化,那么你必须更新树。并不总是需要“重做”整个树。我自己的实现可以在对象移动时根据需要进行更新。天气你能做到这一点取决于你如何实现它。
      • 重做 == 更新;我认为它们是同义词。但你的观点是正确的——这几乎就像你需要一个脏标志来标记改变的部分。
      【解决方案3】:

      如果您有非常动态的数据移动每一帧并且仍然需要加速碰撞检测,我实际上建议使用固定的 3D 网格。二维等效:

      它也可以作为一个空闲列表翻倍以允许恒定时间删除,就像这样(使用next 索引作为同一网格单元中下一个元素的索引或下一个要从中弹出的空闲元素空闲堆栈(如果已被删除):

      另一个例子:

      现在在 3 维中,这似乎需要爆炸性的记忆。然而,诀窍是让每个单元格将一个 32 位索引存储到一个数组中,并且基本上用作一个单链索引列表。这将每个单元的大小减少到 32 位。现在,如果您存储一个 100x100x100 的网格(100 万个单元格),则需要不到 4 兆字节。

      当元素移动时,您可以将它们从它们所在的单元格中移除,移动它们,然后将它们插入新的单元格中。为此,您所要做的就是操作一些 32 位索引(无需内存分配/解除分配将元素从一组单元格传输到其他单元格)。这都是恒定时间的,不需要重新平衡树或拆分变得过于拥挤的八分圆或类似的东西。

      您还可以使用网格层次结构(这可能听起来像八叉树,但有所不同)。我的意思是你的场景中可能有一个粗网格用于整个网格对象。然后每个网格对象可能为其每个部分存储一个粗略的网格,例如 10x10x10。然后每个部分为其每个多边形存储一个精细的网格或八叉树。这允许非有机网格,比方说,刚性的部分像机器人一样旋转,以避免必须更新多边形的精细网格/八叉树,而只需更新其自己的粗糙网格和世界对象的粗糙网格。它开始旋转它的腿和手臂,例如只有有机模型在被骨骼变形时才需要更新它们的精细网格,例如

      我会为你的完全静态的元素/部分保留八叉树,这些元素/部分永远不需要每帧更新,我会使用一个很好的八叉树,稀疏的,可能有一些后处理,用于缓存友好的内存访问。如果您可以假设八叉树在构建后永远不需要更新,那么您有更多时间来加速搜索并最大限度地减少它们的内存使用。

      【讨论】:

      • 我有两个澄清问题。如果一个实体最终重叠了两个图块/正方形(由于宽度/高度),并且它移动了,你如何有效地更新它在网格中的位置?其次,如果所有unique实体可以存储在多个地方,你如何有效地查询它们?
      • 那是相当详尽的。关于所有可能性,我在这里有一个荒谬的冗长答案:stackoverflow.com/questions/41946007/…。最简单的方法是,如果您的代理的大小范围很小,例如您的最大代理没有比您的最小代理大多少,那么您可以在搜索碰撞时使用上限半径或类似的东西特定点的代理。您通过最大代理的上限大小/半径扩大搜索半径...
      • ...这是一种愚蠢的解决方案,但在适当的时候它可以非常有效,而且自然非常简单。当您这样做时,即使您的代理与多个网格单元重叠,您只需将其视为一个点并将其存储在其中心点所在的一个单元中即可。另一种选择是松散结构,在上面的详细答案中,我给出了一个如何做松散网格和松散四叉树的例子(它很容易扩展到三维的松散八叉树)。最后只是将代理冗余存储在它重叠的所有单元格中。如果你这样做,那么棘手[...]
      • [...] 是你想要使用足够大的单元格,这样你就不会像一个巨大的代理那样占据 2000 个网格单元格,这会很糟糕。另一个是你想为代理存储一些轻量级的指针存储——让它尽可能轻。最后,如果您想在存在重叠和冗余时有效地找到唯一实体,一种方法是像布尔值(可能是单个位)一样存储到代理。当您进行查询时,仅当此布尔值设置为 false 时才将代理添加到列表中。如果是,请将其设置为 true。完成后,遍历结果集并设置 [...]
      • [...] 那些布尔值返回 false。这是一种廉价而肮脏的技巧,可以在线性时间内(通过非常便宜的迭代)找到唯一集,而不需要更昂贵的哈希查找或涉及树数据结构来表示唯一集的线性算法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多