【问题标题】:Walk a line between two points in a 3D voxel space visiting all cells在 3D 体素空间中的两点之间走一条线,访问所有细胞
【发布时间】:2013-05-06 12:48:43
【问题描述】:

我有一个视线问题需要通过访问两个(非网格对齐)点之间的 3D 体素空间中的所有可能单元来解决。

我曾考虑使用 3D Bresenham 算法,但它会跳过一些单元格。

一个简单的实现可能只是以比体素网格更高的分辨率检查沿线的点,但我希望有一个更智能的解决方案。

有人有线索吗?

【问题讨论】:

标签: algorithm 3d line voxel bresenham


【解决方案1】:

想出了这个,或查看:http://jsfiddle.net/wivlaro/mkaWf/6/

function visitAll(gx0, gy0, gz0, gx1, gy1, gz1, visitor) {

    var gx0idx = Math.floor(gx0);
    var gy0idx = Math.floor(gy0);
    var gz0idx = Math.floor(gz0);

    var gx1idx = Math.floor(gx1);
    var gy1idx = Math.floor(gy1);
    var gz1idx = Math.floor(gz1);

    var sx = gx1idx > gx0idx ? 1 : gx1idx < gx0idx ? -1 : 0;
    var sy = gy1idx > gy0idx ? 1 : gy1idx < gy0idx ? -1 : 0;
    var sz = gz1idx > gz0idx ? 1 : gz1idx < gz0idx ? -1 : 0;

    var gx = gx0idx;
    var gy = gy0idx;
    var gz = gz0idx;

    //Planes for each axis that we will next cross
    var gxp = gx0idx + (gx1idx > gx0idx ? 1 : 0);
    var gyp = gy0idx + (gy1idx > gy0idx ? 1 : 0);
    var gzp = gz0idx + (gz1idx > gz0idx ? 1 : 0);

    //Only used for multiplying up the error margins
    var vx = gx1 === gx0 ? 1 : gx1 - gx0;
    var vy = gy1 === gy0 ? 1 : gy1 - gy0;
    var vz = gz1 === gz0 ? 1 : gz1 - gz0;

    //Error is normalized to vx * vy * vz so we only have to multiply up
    var vxvy = vx * vy;
    var vxvz = vx * vz;
    var vyvz = vy * vz;

    //Error from the next plane accumulators, scaled up by vx*vy*vz
    // gx0 + vx * rx === gxp
    // vx * rx === gxp - gx0
    // rx === (gxp - gx0) / vx
    var errx = (gxp - gx0) * vyvz;
    var erry = (gyp - gy0) * vxvz;
    var errz = (gzp - gz0) * vxvy;

    var derrx = sx * vyvz;
    var derry = sy * vxvz;
    var derrz = sz * vxvy;

    do {
        visitor(gx, gy, gz);

        if (gx === gx1idx && gy === gy1idx && gz === gz1idx) break;

        //Which plane do we cross first?
        var xr = Math.abs(errx);
        var yr = Math.abs(erry);
        var zr = Math.abs(errz);

        if (sx !== 0 && (sy === 0 || xr < yr) && (sz === 0 || xr < zr)) {
            gx += sx;
            errx += derrx;
        }
        else if (sy !== 0 && (sz === 0 || yr < zr)) {
            gy += sy;
            erry += derry;
        }
        else if (sz !== 0) {
            gz += sz;
            errz += derrz;
        }

    } while (true);
}

【讨论】:

【解决方案2】:

据我所知,最初的 Bresenham 算法假设允许沿对角线移动,在您的情况下禁止它是有意义的。

但主要思想是相同的 - 每个体素都回答“下一步是什么?”的问题

每个体素都有 6 个面,每个面通向不同的邻居。只需检查哪个体素的中心比其他体素更靠近线条。这是下一个体素。

注意:这假设体素沿每个轴具有相同的大小,如果不是这种情况,则应计算修改后的距离(每个分量应除以沿相应轴的体素大小)

【讨论】:

  • 谢谢你给了我一个想法。我想出了这个 jsfiddle.net/mkaWf 不是最佳的,但它可以工作,而且我认为它非常简洁。
  • 你似乎在计算线的参数,当它穿过每个候选平面时。我打算提出这个建议,但是(几乎)平行于某个轴的线存在问题 - 在这些情况下,计算参数的行为非常糟糕,它甚至可能由于计算错误而改变符号。这就是我建议检查距离的原因 - 这是一种更可靠的方法来做同样的事情。
  • 是的,我在下面给出的答案中更新了它,并使用了相同内容的累积版本。即使直线与轴平行,它现在似乎也可以正常运行。
【解决方案3】:

我认为 3d Bresenham 是可行的方法,只是稍作调整。作为解决问题的第一步,使用 Bresenham 进行操作,但当您即将迈出一步或刚刚迈出一步时,请保持怀疑,因为这些地方是线路可能通过额外单元格的地方。

为简单起见,我们假设z 占主导地位,这意味着z 每一步都会递增。 3d Bresenham 问题是:“我们什么时候增加/减少xy?”答案是当 x 中的累积错误达到 0.5 时,或当 y 中的错误达到时,或两者兼而有之。

对于您的情况,我认为您需要有一个使用slopeY = deltaY/deltaZ 的辅助阈值来确定该线是否即将进入相邻单元格。如果stepZ 是每个像素沿线的z 变化,那么像error &gt; .5 - slopeY/stepZ 这样的测试应该告诉您在y 中获取线两侧的单元格。类似的测试会告诉您是否必须在x 中获取额外的单元格。如果您必须在 x 和 y 中都获得额外的单元格,那么您还必须获得与 Bresenham 单元格对角线的单元格。

如果您检测到您在增量之前在y 中添加了一个单元格,那么您将不会在之后添加一个单元格。如果您之前没有添加过y 单元格,则必须在之后添加,除非您碰巧通过了单元格角落。如何处理取决于您的用例。

这些是我对这个问题的想法,我没有测试过任何东西,但类似的东西应该可以工作。

【讨论】:

  • 嗯,谢谢。我要做一个 jsfiddle 看看我能不能完成这项工作
  • @Wivlaro:很好,告诉我进展如何。
  • jsfiddle.net/mkaWf 我有点偏离 Bresenham,我认为它基本上可以工作,并且可能会被优化
【解决方案4】:

这是我最近将体素射线从 C++ 移植到 javascript 的公共链接:

https://github.com/jeremykentbgross/EmpathicCivGameEngine/blob/master/engine/public/scripts/Ray2D.js

注意:该端口目前在四叉树上是 2D 的(而不是在八叉树上是 3D),但这只是因为我的 2D javascript 引擎注释掉了一个维度。它在我的 3D C++ 引擎(我从中移植它的地方)中运行良好,因此如果您取消注释 Z 轴线,它将起作用。该文件还有很多关于数学如何工作的内联 cmets。

您还应该引用 RayTracer2D.js(在同一目录中),它使用射线来查找所有相交的对象及其被击中的交点。

作为参考,它所追踪的四叉树结构也在同一个文件夹中:QuadTree.js

请注意,您还可以通过限制在跟踪期间遍历树的深度来对较低的 LOD 进行光线跟踪。

希望对您有所帮助。

【讨论】:

    【解决方案5】:

    https://code.activestate.com/recipes/578112-bresenhams-line-algorithm-in-n-dimensions/

    这里是 N-D bresenham 线图的一个 numpy 实现,以防有人在谷歌搜索“bresenham 3d python”时遇到这个线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-20
      • 2022-11-23
      • 1970-01-01
      • 2018-06-17
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多