【问题标题】:How to do Ray and Triangle Edge intersect?射线和三角形边缘如何相交?
【发布时间】:2016-08-05 16:18:50
【问题描述】:

我遇到了与三角形边缘相交的问题。实际上,我正在尝试使用鼠标选择/相交网格的三角形、顶点、边缘。所以我从鼠标当前位置制作了射线,然后我将它与三角形/多边形、顶点、边缘等网格元素相交以使用它。基本上,3D建模的东西。与三角形相交既简单又有趣。顶点部分很棘手。

但现在,我不知道如何与三角形边相交/拾取。我的意思是当与鼠标射线相交时我如何对待它们?首先,我认为可以将它们视为 3D 线。但最终未能做到 Ray 和 Line 相交。在互联网上搜索但没有找到任何有用的信息。虽然我发现一些开源项目正在使用 OpenGL 内置的拾取功能来拾取/与 Edge 相交。但就我而言,我不能使用它。 :(

我当前的边缘拾取代码结构如下所示:

void pickEdge(Ray ray, Scene scene)
{
    for each object in scene
    {
        mesh = getMesh(object)
        for each triangle in mesh
        {
            for each edge in triangle
            {
                v1 = getV1(edge)
                v2 = getV2(edge)

                // Do intersect with 'ray' and 'v1', 'v2'. But how?
            }
        }
    }
}

所以我被困在这里,真的需要一些帮助。非常感谢任何想法、算法或小帮助。

【问题讨论】:

  • 确定您的拾取点是否在可接受的边缘“半径”内 - 使用距离到线的公式。然后对边缘进行正交投影,以在必要时在边缘上产生一个“点”。
  • @Brett Hale 你说'使用距离公式'。实际上我被困在这一点上。事实上,我还不能实现 Ray-Line 相交。如果您将其发布为包含更多详细信息的答案,将会更有帮助。感谢您的宝贵意见:)
  • 啊...其实我还是卡住了:(需要帮助...拜托。

标签: algorithm math 3d intersection ray-picking


【解决方案1】:

在您的情况下,在 3D 空间中查找三角形和射线之间的交点的问题可以归结为在 2D 空间(平面)中的三角形中查找点位置(INSIDE、OUTSIDE、ON BOUNDARY)。您应该做的就是在屏幕平面上投影三角形,在边缘找到交点并在边缘进行反向投影。点的位置是鼠标的位置。唯一的问题是处理退化的情况,例如将三角形映射到线段。但我认为这不会有问题,因为这样的情况很容易应付。

【讨论】:

    【解决方案2】:

    请查看本页末尾的算法以及本网站提供的所有算法:http://geomalgorithms.com/a05-_intersect-1.html

    【讨论】:

    • 哇!这些算法真的非常有用。我必须看看我是否可以明智地使用它们来解决我的问题......谢谢。
    【解决方案3】:

    第一种方法是将边缘(和光线)正交投影到垂直于光线的平面上,然后计算投影光线到投影边缘的距离。

    即,首先你确定两个正交向量rdir1, rdir2 与你的射线正交。

    然后你计算你的射线(它的基点)到这个平面的投影,这将简单地产生一个二维点rp

    然后您将边缘投影到该平面,只需应用点积即可: pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2)) pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))

    现在您可以计算从这条二维线pv1, pv2 到点rp 的距离。

    假设边缘的方向取自视图矩阵的“前向”方向,则与之正交的两个向量将是视图矩阵的左右向量。

    执行上述方法将产生类似于将边缘投影到屏幕上的效果。因此,您也可以将边缘投影到屏幕上并使用这些坐标。

    【讨论】:

    • 嗯...我认为我的问题可以通过简单的 3D (xyz) 数学来解决。但现在,事情似乎不会那么容易了。事实上,我很少理解正交投影,将某些东西投影到……平面……东西……等等。确实,在这些情况下,掌握数学是最重要的。而我,我,我自己;总是卡在这一点上:(...你明白我的意思吗?无论如何感谢这个更好的答案。让我看看我是否能解决我的问题。哦..我现在没有太多时间了。但是谢谢!
    • 您好 Mohammad,不要被冗长的回复吓倒。这真的很简单。确实有不同的方法(通过使用叉积),但答案已经太长了。如果你在乎,我会添加其他路线。
    • 当然。事实上,我很高兴从您那里获得更多信息。问候。
    【解决方案4】:

    首先,两个几何对象 A 和 B 之间的距离是多少?它是 A 和 B 上任意两点之间的最小距离,即。 dist(A,B) = min { EuclideanLength(x - y) | x in A, y in B}。 (如果它存在并且是唯一的,在您的情况下就是这样。)

    这里EuclideanLength((x,y,z)) = sqrt(x^2 + y^2 + z^2) 你已经知道了。因为sqrt 是严格增加的,所以将SquareEuclideanLength((x,y,z)) = x^2 + y^2 + z^2 最小化就足够了,这大大简化了问题。

    在您的问题中,对象是线段A := {v1 + t*(v2-v1) | 0 <= t <= 1} 和线B := {p + s*d | s is any real number}。 (别担心你问的是一条射线,一条线才是你真正想要的。)

    现在计算距离归结为找到合适的ts 使得SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) 最小,然后计算EuclideanLength(v1 + t*(v2-v1) - p - s*d) 以获得实际距离。

    为了解决这个问题,我们需要一些解析几何。因为d 不为零,我们可以将每个向量v 写成与d 正交的部分和d 的倍数的部分之和:v = Ov + Mv。对于这样的“正交分解”,它始终保持SquareEuclideanLength(v) = SquareEuclideanLength(Ov) + SquareEuclideanLength(Mv)

    因为上面有d = Md

    SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d) = SquareEuclideanLength(Ov1 + t*(Ov2-Ov1) - Op) + SquareEuclideanLength(Mv1 + t*(Mv2-Mv1) - Mp - s*d)

    左加数不依赖于s,但是你选择了t,你可以找到一个s,这样右加数是0! (记住Mv1Mv2、...是d的倍数。)

    因此要找到最小值,您只需要像上面那样找到这些地图OM 并找到最小化器t

    假设d 是标准化的,这些实际上是由Ov := CrossProduct(v, d)Mv := DotProduct(v, d)*d 给出的,但请相信我,如果d 未标准化,这也有效。

    所以现在找到距离的方法是:找到最小化的0 <= t <= 1

    SquareEuclideanLength(Cross(v1 - p, d) + t*Cross(v2 - v1, d)) = SquareEuclideanLength(Cross(v1 - p, d)) + 2*t*Dot(Cross(v1 - p, d), Cross(v2 - v1, d)) + t^2 SquareEuclideanLength(Cross(v2 - v1, d)).

    您已经从 Point-Line 距离计算中知道了这个公式(就是这样),它是通过对 t 进行微分并等于 0 来解决的。

    所以这个方程的最小值是 t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))

    使用此t,您可以计算v1 + t*(v2 - v1),即线段 A 上最靠近线 B 的点,您可以将其插入点线距离算法以找到所需的距离。

    希望对你有帮助!

    【讨论】:

    • 非常感谢您提供所有这些信息!最好的问候:)
    猜你喜欢
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    相关资源
    最近更新 更多