3

正常行进立方体每个立方体找到 12 条边,但您可以为每个立方体做 3 条边,将边保存在数组中,然后再次遍历立方体,参考相邻立方体的边而不是计算它们。

Internet 上并未明确讨论引用相邻立方体的过程,因此欢迎使用行进立方体的任何人帮助查找解决方案的详细信息。你知道一个实现吗?

这是一张图片,显示了每个立方体所需的 3 个黄色边缘,而不是 12 个。

图片

编辑-我刚刚找到了这个解决方案,尽管它只是其中的一部分:

想象一下来自坐标最低的立方体角的 3 条边。然后所有其他边只属于其他立方体。如果我们的立方体有坐标 (x,y,z),相邻的立方体有坐标 (x+1,y,z), (x,y+1,z), (x,y,z+1), (x +1,y+1,z), (x+1,y,z+1), (x,y+1,z+1)。你可以把边缘想象成一个向量。然后立方体的角有边缘(1,0,0),(0,1,0),(0,0,1)。坐标为 (x+1,y,z) 的立方体具有属于我们立方体的边 (0,1,0) 和 (0,0,1)。立方体 (x+1,y+1,z) 只有一条边 (0,0,1) 属于我们的立方体。因此,如果您为多维数据集存储 4 个元素,您可以像这样访问它们:

edge1 = cube[x][y][z][0];
edge2 = cube[x][y][z][1];
edge3 = cube[x][y][z][2];
edge4 = cube[x+1][y][z][1];
edge5 = cube[x+1][y][z][2];
edge6 = cube[x][y+1][z][0];
edge7 = cube[x][y+1][z][2];
edge8 = cube[x][y][z+1][0];
edge9 = cube[x][y][z+1][1];
edge10 = cube[x+1][y+1][z][2];
edge11 = cube[x+1][y][z+1][1];
edge12 = cube[x][y+1][z+1][0];

现在 edge7 连接哪些点?答案是 (x,y+1,z) 和 (x,y+1,z)+(0,0,1)=(x,y+1,z+1)。

现在哪些立方体 edge7 连接?它更难。我们看到坐标 z 是沿边缘变化的,这意味着 neibour 立方体具有相同的 z 坐标。现在所有其他坐标都发生了变化。在我们有 +1 的地方,立方体有很大的坐标。在我们有 +0 的地方,立方体的坐标更小。所以边连接立方体 (x,y,z) 和 (x-1,y+1,z)。其他 2 个具有相同边的立方体是 (x,y+1,z) 和 (x-1,y,z)。

-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=

EDIT2-所以我正在这样做,它并不是那么简单。我有一个循环,它同时计算 8 个点、12 条边、边的插值、位值和边的值的顶点,所有这些都在一个循环中。

所以我在它之前做了一个新的循环来尽可能多地计算并将它放在数组中以在复杂的循环中使用。

我可以在数组中回收沿边缘的交点的插值,尽管我将不得不在复杂的循环中再次重新计算所有点,因为我用来决定引用顶点中值的位数的点的值桌子。这让我很困惑!我认为一旦我有了边缘交点值,我可以直接使用它们来获取三角形表,而无需重新计算点!

事实上没有。无论如何,这里有一些已经做过的人的信息,只要它是可读的! http://www.new-npac.org/projects/sv2all/sv2/vtk/patented/vtkImageMarchingCubes.cxx 滚动到这一行:立方体负责其最小面上的边缘。

4

3 回答 3

2

以您建议的方式减少边缘计算的一种简单方法是一次计算一个轴对齐平面的立方体。

如果您将所有立方体及其边保存在内存中,则只需计算每条边一次并通过索引找到相邻边会很容易。但是,由于空间要求,您通常不希望一次将所有多维数据集保存在内存中。

一个解决方案是一次计算一个立方体平面。即轴对齐的横截面,从一侧开始,向另一侧发展。然后,您一次只需要在内存中最多保留两个完整的立方体平面。当您穿过每个平面时,您可以参考前一个平面中的共享边和当前平面中先前计算的立方体。当您移动到下一个飞机时,您可以取消分配您不再需要的飞机。

编辑:本文讨论了我的建议: http ://alphanew.net/index.php?section=articles&site=marchoptim&lang=eng

于 2015-04-18T23:48:20.517 回答
1

有趣,因为当我实现自己的 MC 时,我想出了类似的解决方案。

当您开始使用 MC 时,您将它们视为不同的立方体,但如果您想获得高性能,您需要将整个网格作为一个整体创建,而创建顶点索引等在这里并不容易。当您想要添加平滑的逐顶点法线时,它会变得更加有趣:)。

为了解决这个问题,我创建了一个简单的索引缓存机制来存储每个边的顶点索引。然后,对于每个计算的边缘,我有立方体位置 x、y、z 和边缘索引,我执行以下操作:

For each axis:
    if the edge is on '+' side of axis:
        replace edge index with its '-' side sibling
        increment cube position along axis

这个简单的操作为我提供了正确的立方体位置和 0、1、2 的边缘索引。然后我通过简单的位旋转从 x,y,z,edgeIndex 值计算总缓存索引。

当我有缓存索引时,我检查它是否大于-1。如果是,那么在这个边缘已经有一个计算的顶点,我可以重用它。如果它是-1,我需要创建一个新顶点并将其索引存储在缓存中。这样,您将只计算每个顶点一次,您甚至可以添加一个在包含您的顶点的每个三角形之间共享的法线值。

于 2014-02-13T13:21:04.003 回答
1

是的,我认为我这样做类似于 kolenda。我有一个包含 5 个整数的结构:(立方体)索引和 4 个顶点索引(A、B、C、D)。

对于最内部的循环 (x),我只有 lastXCache 和 nextXCache。在指向 -x 方向的 4 条边上,我询问是否 lastXCache.A != -1,如果是,则分配先前计算的值等。在 +x 方向上,我将计算的顶点存储在 nextXCache 中。当多维数据集完成时:lastXCache = nextXCache; 对于 y 和 z 方向,它需要是一个列表(可变数组的统一术语),下一个 y 是下一行(所以 sizex),下一个 z 是下一个平面(所以 sizex * sizey)

唯一的缺点是,这样它必须逐个运行立方体,如此连续地运行。但是您可以并行计算不同的块。

我认为可能更平行的另一种方法需要2遍:1.计算每个立方体的3条边,当1完成时-> 2.绘制三角形。

真的不知道什么更好,但它实际工作的方式似乎足够快。与统一工作更好。为 1 个块/网格创建一个 IJob。

于 2020-11-02T14:03:01.643 回答