【问题标题】:Fast algorithm to calculate 3D ray / triangle edge intersections for a large number of triangles计算大量三角形的 3D 射线/三角形边缘交点的快速算法
【发布时间】:2017-06-30 13:17:55
【问题描述】:

我在 3D 空间中有一个三角形 ABC,并且在由起点 E(总是在三角形的边缘内或三角形的边缘上)和方向向量 d 给出的三角形平面内有一条射线。

顶点 A、B 和 C 以及 E 和 d 在 3D 坐标 {x,y,z} 中给出。

我正在寻找一种算法来计算射线与三角形边 P 的交点。

我可以对三角形的 3 条边进行 3 次射线/线段相交测试,但由于我必须对大量三角形执行此操作,因此我正在寻找一种更高效、更快的算法。

  1. 最好的方法是什么?
  2. 重心坐标有帮助吗?

【问题讨论】:

  • 在 [math-stackexchange][1] 中计算这三个交集测试的复杂性在 O(1) 中。我怀疑(2)更改坐标系会对您有很大帮助。 (1) 更有趣的是你的意思是什么:“我必须为大量的三角形做这个”。也许您可以添加您正在处理的其余问题以简化提供建议。 [1]:math.stackexchange.com/questions/2139740/…
  • 您必须在空间上对三角形进行分组,并仅检查射线附近的组...在相机方向 Z 顺序中
  • 按照我的阅读方式,您基本上处于二维设置中:您的所有点似乎都在一个平面上。对吗?
  • 光线总是一样的吗?射线和三角形是共面的吗?

标签: algorithm graphics 3d geometry computational-geometry


【解决方案1】:

看论文

Fast, minimum storage ray-triangle intersection, Tomas Möller 和 Ben Trombone, 在 图形工具杂志,1997 年 2(1):21–28。

另见this page。

作者说:

这种方法的一个优点是平面方程不需要即时计算也不需要存储,这可以显着节省三角形网格的内存。由于我们发现我们的方法在速度上与以前的方法相当,因此我们相信对于没有预先计算平面方程的三角形来说,它是最快的射线-三角形相交程序。

【讨论】:

    【解决方案2】:

    暂时忽略 d 具有最小分量的轴,并处理由此产生的 2D 问题,就像我们在您的插图中看到的那样。

    您可以预先计算射线支持线的方程,形式为 ax + by + c = 0(假设 z 被忽略)。将三个顶点的坐标代入这个表达式,符号会告诉你顶点在直线的哪一边。

    与线的两个交点出现在端点处具有不同符号的边上。

    然后,要确定哪个是右边缘,光线和第三个边缘之间的角度符号就可以了(如果我是对的);

    当你知道哪条边时,你可以计算边的参数方程的参数,你可以从之前计算的符号中推导出来。例如,沿着边 AB,t = Sb / (Sb - Sa)。也计算 1 - t;

    最后,使用 t 值在端点之间进行插值,这次是 3D。

    计算成本为

    • 对Sa、Sb、Sc三个符号求值,取6+和6x;

    • 选择两个候选边缘,进行两个或三个比较;

    • 选择单个候选者,取 2D 叉积,3 + 和 2 x 并进行比较;

    • 插值参数的计算,2+,1/;

    • 最终 3D 插值,3 +,6 x。

    将很难做得更短。

    【讨论】:

      【解决方案3】:

      重心坐标有帮助吗?

      可能。这在一定程度上取决于您的非重心代码的优化程度,但我想说的是,使用重心坐标至少更容易编写可维护和高性能的代码。

      据我所知,您的整个设置基本上是二维的,点E 和方向d 都包含在A,B,C 跨越的平面内。所以你有

      E = aE*A + bE*B + cE*C  with aE+bE+cE=1
      d = ad*A + bd*B + cd*C  with ad+bd+cd=0
      

      现在你有两个子问题:

      1. 如何高效获取重心坐标
      2. 如何找到交点

      让我们从后者开始。您只需将d 的倍数添加到E,直到c 坐标变为零。

      P = E - (cE/cd)*d
      

      根据您的设置,您也可以使用齐次坐标,在这种情况下,您可以将其写为 P = cd*E - cE*d。

      如何将d 和E 的x,y,z 坐标转换为重心a,b,c?嗯,这只是一个线性方程组。您可以使用由向量A,B,C 形成的矩阵的逆矩阵。同样,如果您正在处理齐次坐标,则可以使用辅助而不是逆。

      这里是同质化方法的详细说明:

      aE = (By*Cz-Bz*Cy)*Ex + (Bz*Cx-Bx*Cz)*Ey + (Bx*Cy-By*Cx)*Ez
      bE = (Cy*Az-Cz*Ay)*Ex + (Cz*Ax-Cx*Az)*Ey + (Cx*Ay-Cy*Ax)*Ez
      cE = (Ay*Bz-Az*By)*Ex + (Az*Bx-Ax*Bz)*Ey + (Ax*By-Ay*Bx)*Ez
      ad = (By*Cz-Bz*Cy)*dx + (Bz*Cx-Bx*Cz)*dy + (Bx*Cy-By*Cx)*dz
      bd = (Cy*Az-Cz*Ay)*dx + (Cz*Ax-Cx*Az)*dy + (Cx*Ay-Cy*Ax)*dz
      cd = (Ay*Bz-Az*By)*dx + (Az*Bx-Ax*Bz)*dy + (Ax*By-Ay*Bx)*dz
      aP = cd*aE - cE*ad
      bP = cd*bE - cE*bd
      Px = aP/(aP+bP)*Ax + bP/(aP+bP)*Bx
      Py = aP/(aP+bP)*Ay + bP/(aP+bP)*By
      Pz = aP/(aP+bP)*Az + bP/(aP+bP)*Bz
      

      前三行将E 转换为重心坐标,接下来的三行d。然后我们计算P 的重心坐标,并将它们转换回笛卡尔坐标。在该步骤中,我们还将它们去均质化,即除以重心坐标的总和。

      总的来说,这里有相当多的代码。您可以通过将常用表达式移至专用变量来减少操作数量,尤其是在您的编译器不为您执行此操作的情况下。一个好处是您不需要任何除法,除了最终的去均质化,即(a+b) 的除法。如果你计算一次1/(a+b),你可以只用一个除法,这对性能有好处。

      然而,上述代码的真正好处可能是您可以使用重心坐标完成许多其他坐标系无法轻松完成的好事情。例如,如果您想检查光线是否击中线段上的线AB 或三角形外的某处,只需检查是否aP*bP > 0。

      【讨论】:

      • 我们以三角形为例:(Ax=0, Ay=0, Az=0), (Bx=5, By=0, Bz=0), (Cx=0, Cy=5 , Cz = 0)。让我们将 E 设置为 (Ex=1, Ey=2.5, Ez=0) 并将 d 设置为 (dx=1, dy=0, dz=0)。那么我们应该得到与边 BC 的交点:(Px=2.5, Py=2.5, Pz=0)。重心坐标用于 E (aE=0.3, bE=0.2, cE=0.5) 和 d (ad=0.8, bd=0.2, cd=0)。对于与边 BC 的交点,重心坐标 a 必须为零。因此我们得到 P = E - (aE/ad)*d = (Px=0.625, Py=2.5, Pz=0) 这是不正确的。我的错在哪里?
      • @user3384674:您问题中的图片与边缘 AB 相交,而我的代码始终与 AB 相交。要与 BC 相交,您需要更改一些标签。但我意识到将 d 和 E 转换为重心坐标时我犯了一个错误。在您的示例中 Az=Bz=Cz=0 所以矩阵 ABC 有一个零行并且没有逆矩阵。实际上,需要多一行来确保 aE+bE+cE=1 和 ad+bd+cd=0,这使得这些系统过度定义,因为只有当 E 在 A、B、C 跨越的平面内且 d 平行于那架飞机。
      【解决方案4】:
      1. 时间复杂度为 O(1)
      2. 它可能会有所帮助。 如果我们谈论的是 3D,而您的所有点都位于一个平面上。在笛卡尔坐标中,您需要求解三个线性系统 以找到与三条线的交点,然后确定交点是否位于边上。 或者你需要在线上找到两点的重心坐标。点 A(a1,a2,a3) = E 和 B(b1,b2,b3) = E+d。线方程是 现在您仍然需要求解三个线性系统(其中一个 mu = 0,其他的总和 = 1)。但更容易解决的将是 2x2 系统。然后检查找到的根的符号以确定找到的点是否在边缘。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-30
        • 1970-01-01
        • 1970-01-01
        • 2018-01-09
        • 1970-01-01
        • 2014-05-03
        • 2017-09-23
        相关资源
        最近更新 更多