【问题标题】:Are there any good techniques for keeping nearly-sorted data nearly-sorted?有没有什么好的技术可以保持几乎排序的数据接近排序?
【发布时间】:2012-06-26 18:27:38
【问题描述】:

短版:

我正在寻找一种技术,使几乎排序的数据随着时间的推移保持接近排序的顺序,尽管值略有变化。

这是场景:

在 3D 图形的世界中,在绘制之前将对象从前到后排序通常是有益的。随着您的场景发生变化或您的场景视图发生变化,这些数据可能需要重新排序,但是它通常会非常接近排序顺序(即,它不会在帧之间发生太大变化)。数据是否完全按排序顺序也不是很重要。将发生的最糟糕的事情是多边形将被渲染然后完全隐藏。这是一个小的性能损失,但不是世界末日。

考虑到这一点,是否可以提前对数据进行一次排序,然后每帧对数据应用一次最小的补丁,以确保数据保持大部分强>排序?在这种情况下,如果大多数对象按升序排列,则认为数据大部分已排序。也就是说,距离正确位置 10 步的 1 个对象比距离正确位置 1 步的 10 个对象好多(好 10 倍)。

还值得注意的是,数据可以继续半定期修补,因为数据通常每秒渲染 30 次(左右)。只要计算是有效的,它就可以随着时间的推移继续进行,直到更改停止并且列表完全排序。

现有想法:

我对这个问题的下意识反应是:

  1. 在加载数据时对数据应用n log n 排序,并对大的更改(我可以很容易地跟踪)进行排序。

  2. 当数据开始缓慢变化时(例如,当场景旋转时),对数据应用某种类型的单个(线性)传递以向后交换邻居并尝试保持排序顺序(我认为这基本上是 shell 排序 -也许有更好的算法可用于单次通过)。

  3. 继续对每一帧进行一次部分排序,直到更改停止并且数据完全排序

  4. 返回第 2 步,等待更多更改。

【问题讨论】:

    标签: algorithm sorting opengl data-structures 3d


    【解决方案1】:

    如果输入大部分已排序,则有多种排序在 O(n) 时间内运行,如果数据未排序,则在 O(n log n) 时间内运行。听起来你可以很容易地使用它。 Timsort 就是这样一种排序,我相信它现在是 python 和 java 中的默认排序。 Smoothsort 是另一种很容易自己实现的方法。

    【讨论】:

      【解决方案2】:

      从您的描述看来,排序顺序会发生变化,而无需您更改数据本身。例如。你改变了相机,所以排序顺序应该改变,即使你没有修改任何多边形。

      如果是这样,您无法在排序顺序更改发生时直接检测到它们。如果可以的话,我会为多边形列表创建存储桶,并在该存储桶中的“足够”多边形被触及时使用存储桶。

      但我敢打赌,您的系统不会这样工作。排序由视口确定。在这种情况下,排序前面的多边形比最后的多边形更重要。

      所以我会将多边形列表分成五分之一或类似的东西。从前到后,所以前五分之一是最靠近相机的部分。我会对每一帧的第一段进行完全排序。我将第二段划分为子段 - 再次说 5 - 并在每一帧对每个子段进行排序,这样每 5 帧第二个第五个被完全排序。将第三到第五段分割成 15 个子段,每 5 帧执行一次,以便每 75 帧对其余部分进行完全排序。在 60 fps 时,显示列表每秒会完全恢复一次以上。

      优先考虑列表前面的好处是 1. 前面的多边形在屏幕上往往会更大,并且会更频繁地无法通过深度测试。列表末尾的错误订单通常并不重要。 2. 列表的前面更容易因相机变化而发生排序变化。

      还选择了那些有少许重叠的线段范围,以便多边形可以以两种方式迁移到正确的线段。

      @OP:再想一想。您可能更关心排序成本保持有限 - 而不是场景复杂性爆炸。特别是因为一个非常复杂的场景应该 - 令人惊讶的是 - 不太容易受到不良排序的影响(因为通常多边形会变小)。

      您可以为每帧定义一个固定数量的排序。将预算的 50% 用于尽可能多的列表前面的区域,将预算的 25% 用于对下一个区域进行排序,将 25% 的预算用于其余区域。

      假设您预算每帧排序 1000 个多边形,而场景中有 10000 个多边形。每帧对前 500 个多边形进行排序。为下一个区域每十帧排序 250 个多边形。所以第 1 帧为 501-750,第 2 帧为 751-1000 等等。然后将列表的其余部分划分为 250 个帧段,并根据需要对它们进行循环排序。

      这使排序成本保持不变,场景变得越来越复杂,并且易于调整,您只需将排序预算调整到您可以承受的范围内。

      【讨论】:

      • 你是对的,如果不重新计算,我无法检测到哪些项目发生了变化。事实上,当发生旋转时,几乎每个距离都会发生变化(仅会排除枢轴位置的对象)。这是一个非常有趣的想法。我想知道是否有人以前做过这样的事情。
      • 不错的想法,但在细节上有一些可修复的缺陷:您声称第二段每 5 帧进行一次完全排序。这不是真的,因为您的提案不允许子段之间移动,只允许内移动。本着这种精神的最佳解决方案可能是将排序段 a .. b 替换为排序段 a-n .. b+n 无处不在,其中 n 可能以某种方式取决于段长度 b-a - 例如(b-a)/10.
      【解决方案3】:

      我将在这里提出一个借鉴其他许多人的解决方案。当然,我们从初始化时的完整对象开始。

      我会做的是总是对每一帧的对象执行 10 次线性时间运行(如果您发现对象已经完全排序,则提前终止)。例如,每次运行都可以是 bubble sort 的一次传递,在整个数组上具有 shell sort 样式的间隙:对于从 0 到 n-gap-1 的所有 i,比较 A[i] 和 A[i+gap] ,如果没有排序则交换它们。您可以使用固定的间隙序列,或者更好的是,让它在帧之间变化;无论哪种方式,如果您在对象不变的情况下制作了足够多的帧,那么您将拥有一个完全排序的序列。您甚至可以混合不同类型的子算法来运行,只要每次迭代都能提高“排序性”。

      您可以添加 Rafael Baptista 的想法,即通过在前段多跑一次,或者选择将前半部分的间隙除以 2 或类似的方式,轻松地优先考虑场景的前部。

      【讨论】:

        【解决方案4】:

        它并没有像您想象的那样巧妙地解决问题,因为您所要做的就是将相机旋转 90 度,并且排序的基础完全在不同的轴上。 (X和Y轴是独立的,例如——向下看X轴会导致排序顺序不依赖X轴,向下看Y轴会导致排序顺序不依赖Y轴。)即使是 5 度的转弯也会导致远处的“接近”(就 Z 顺序而言)事物突然变得“遥远”。

        说实话 - 为对象生成绘制调用通常比对它们进行排序花费更多时间,尤其是如果您有针对您的场景优化的排序算法并且您的游戏具有现代视觉复杂性。

        排序实际上可以是 O(n),尤其是对于基于直方图的算法或基数风格的算法。 (是的,基数排序适用于整数,所以你必须将你的世界坐标缩放为整数,但通常这已经足够了,除非你有一个巨大的世界。)

        话虽如此,由于您已经对绘制的所有内容进行了 O(n) 次操作,因此每帧都不会成为一个大问题,尤其是在高级和低级优化的情况下。

        解决此问题的另一种常见方法是使用scene graph,但出于您的目的,它最终基本上是每帧重新排序。但是,您可以将平截头体剔除、阴影剔除和细节级别计算构建到场景图遍历中。

        如果您正在寻找近似值,而不是进行 z 距离排序,请执行真正的距离排序,并更频繁地更新排序顺序以用于靠近的对象,而不是更频繁地用于更远的对象(取决于相机行进的距离) .这可以起作用,因为如果您离对象较远,移动不会导致观察者的角度经常发生变化,这反过来意味着旧的排序数据更有可能是有效的。我不喜欢这个,因为我喜欢允许我的游戏在地图上传送而没有任何问题的算法。 (请注意,从磁盘流式传输资产成为传送的真正问题。)

        【讨论】:

        • 首先,我的场景是用鼠标旋转的,所以我假设我可以在用户将其旋转 90 度之前平滑排序。对于您描述的teleport 场景,我同意您的评估。但这可以作为一种特殊情况处理(使用完整的排序)。这些场景应该不那么频繁且容易枚举(至少在我的应用程序中)。我的game 实际上只是一个显示球棒图的应用程序......大的。
        • 您首先指向从沿 x 到沿的大约 90 度旋转,导致排序仅取决于 x 或 y 坐标 - 仅在特殊情况下为真 - 您的相机角度为 180 度。使用 90 度相机仍然存在关系。例如,当您向下看时,x 轴远且 y 轴近的对象很小并且靠近显示列表的末尾。转动 90 度只会使其旋转离开屏幕。或者考虑一下 1 度的相机角度会发生什么 - 除非场景或相机原点发生变化,否则不会发生任何变化。
        【解决方案5】:

        Shell sort 适用于唯一值很少的列表和一些“需要短代码且不使用调用堆栈”的场景。

        在您的情况下,您需要一个名为 Adaptive sort 的东西,这意味着算法“利用其输入中的现有顺序”。

        如果你的空间很紧,你可以直接使用Straight Insertion Sort,它是自适应且就地的。

        否则您可以按照@RunningWild 的建议尝试 Timsort 和 Smoothsort,它们都是自适应排序算法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-06-16
          • 2019-05-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多