确定一个点是否在三维空间中的三角形内部

10

我希望确认一种方法,用于确定一个点是否位于三维空间中的三角形内。给定一个以R(t) = e + td形式表示的射线和由三个点T = {V0, V1, V2}构成的三角形集合,我知道如何找到这三个点所形成平面的参数方程,以及如何确定射线是否与该平面相交。最后,如果相交,我想知道交点是否实际上在三角形边界内。

请看下面的图片。

enter image description here

我的想法是,可以计算每条边向量与从第一条边向量指向该点的向量之间的点积,并检查它们是否全为正数。就像这样:

enter image description here

如果是这样,那么该点应该位于三角形内。对吗?这不是计算机图形学中用于确定背面的相同方法吗?


我构建了一个示例来测试该方法,似乎它有效了…至少在这种情况下是。我仍在寻找最终的答案。 我构成的三角形由顶点 {P0,P1,P2} = {(0,0,0),(5,0,5),(5,0,0)} 组成,我让点 w = (3,-5,0) 和 u = (5,5,5) 形成一条线,我知道这条线会在某个点与三角形相交。 - Great Cubicuboctahedron
2
这是不正确的;点积检查只在边界为直角时有效。 - user3235832
@willywonka_dailyblah,如果我让向量逆时针旋转,就像我在文本和上面的图片中描述的那样,我不明白为什么会有问题?你能否解释一下你的意思? - Great Cubicuboctahedron
点积只有在角度大于90度时才为负;显然,三角形中的角度可以比这个小,因此您可能会检测到刚好位于三角形边缘之外的点,但也会错过那些在钝角三角形内部的点。 - user3235832
网络上有很多资源,例如在这里查看:http://www.blackpawn.com/texts/pointinpoly/ - user3235832
@willywonka_dailyblah 谢谢你的回复。你介意看一下我在下面答案的评论中的链接吗? - Great Cubicuboctahedron
4个回答

8

在图形学中,人们通常使用重心坐标系。在您的情况下,P 可以描述为 P = aV0 + bV1 + cV2,其中 a + b + c = 1。当且仅当 0 <= a, b, c <= 1 时,P 在三角形内。

如果由 v1、P、v2 组成的三角形的面积为 S1,由 P、v0、v2 组成的三角形的面积为 S2,并且 P、V0、V1 的面积为 S3。那么 a = S1/Sb = S2/Sc = S3/S,其中 S 是三角形 V0、V1、V2 的面积。

要找到 S = 1/2||(V0-V1)creosspdoruct(V0-V2)|| 的面积。

您可以查看我网站上发布的教程


谢谢您的回复,我一定会查看您的教程!您介意看一下这个页面上的第三种方法吗?http://totologic.blogspot.se/2014/01/accurate-point-in-triangle-test.html 这种方法与我提出的方法有什么不同之处? - Great Cubicuboctahedron
另外,我找到了这个网站:http://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/ray-triangle-intersection-geometric-solution 引用:“为了确定 P 是否在三角形内部,我们可以测试沿着边缘的向量和由测试边的第一个顶点和 P 定义的向量的点积是否为正(意味着 P 在边缘的左侧)。如果 P 在所有三条边的左侧,则 P 在三角形内部。” - Great Cubicuboctahedron
1
你确定你的设置是一样的吗?在第三个方法中,你不应该找到v0v1和v0p的点积。看起来你需要按照教程描述找到左正交于v0v1的点积:为此,首先我们需要考虑三个向量v1、v2和v3,它们分别是[p1,p2]、[p2,p3]和[p3,p1]的左正交向量:v1 = <y2 - y1, -x2 + x1> v2 = <y3 - y2, -x3 + x2> v3 = <y1 - y3, -x1 + x3> - Good Luck
1
在您发送的第二个链接中,您还需要找到v0p和vov1的叉积。 - Good Luck
好的,我想我明白了。所以,我不是按照我提出的方式来做,而是计算每个边向量与从第一个边向量指向该点的向量的叉积,然后计算叉积结果和平面法向量的点积..? - Great Cubicuboctahedron

5

我有点晚到(抱歉),但是我对此有些看法:

我曾在80年代进行射线追踪。当时,我提出了一种与您讨论的相似的解决方案。

想法是,如果一个点始终位于三角形的边缘上逆时针行走的观察者右侧,那么该点就在三角形内部。

为此,我们需要测试是否每个边缘的右侧都存在该点。 叉积很好用,但是正如它所指出的那样,叉积会给你一个cos值。 您想要的是sin,因此可以拒绝具有负测试的点。 这就是人们倾向于使用叉积而不是点积的原因。 但是,叉积需要比点积更多的计算(在80年代这非常重要!)

但是我们可以通过简单的90度旋转将cos转换为sin! 因此,我们不是计算点积而是在多边形平面中从边缘旋转90度的线计算它。

起初看起来很麻烦,但如果我们在主平面之一中工作,如XY、YZ或XZ,则不会。因此,让我们在其中一个主平面上以2D方式工作,而不是在三角形平面中以3D方式工作。如果一个点在3D中的多边形内部,它也将在其在2D平面上的投影内部。当然,如果多边形与其中一个主平面平行,如果我们在错误的平面上进行投影,可能会有问题。

因此,要选择这个平面,只需查看三角形的法线并选择更靠近三角形平面的平面。如果X分量最大,则使用YZ平面等等...此外,该分量的符号将告诉我们投影的多边形是顺时针��是逆时针。

在这些2D平面中,边的90度旋转只是交换值,并在其中一个值上改变符号。

例如,在XY平面上,V0和V1之间的边缘是:

V0V1x = v1x - v0x

V0V1y = V1y - v0y

V0和P之间的向量是:

V0Px = Px - V0x

V0Py = Py - V0y

将边旋转-90度,得到x' = y和y' = -x;

因此,我们计算第一条边的标量积为:

Scalar = (Px - V0x) * (V1y - V0y) + (Py - V0y) * (V0x - V1x)

如果该值小于0,则该点不在内部。

您可以使用另外两条边进行同样的操作,以完成“内部”测试。

在我的解决方案中,我预处理了一个值,用于给出每个三角形的最大法向量和符号。之后,我使用该值来确定要计算交点的平面。(负法向分量使我切换三角形的“顺时针”方向)。

检查点是否在多边形内部需要:

  • 进行1个“方向”测试,最大正常值(一个有6种情况的开关,XY、XZ或YZ,正数或负数)

  • 进行3个“边缘”测试,每个测试包括4次减法和2次乘法以及1个测试。

如果点在多边形内部,则只需进行3次“边缘”测试。否则,在第一次或第二次“边缘”测试后可能会被拒绝...

因此,知道一个点是否在三角形内需要8到22个操作。

我现在看到的大多数解决方案似乎使用的操作比这还要多!


1
你想解决。
E + t.D = a.V0 + b.V1 + c.V2

where

t, a, b, c >= 0, a + b + c = 1

使用c = 1 - a - b,您可以得到一个3x3线性系统(分解为xyz

a.(V0 - V2) + b.(V1 - V2) - t.D = E - V2

如果你能解决t, a, b的问题,然后检查c是否为正数,那就太好了。


0

您可以使用点积来确定一个点是否在三角形内。首先找到测试点在每条边上的投影。点积的符号只有在直角时才有意义,而投影将给您一个直角。

对于三角形abc和点p,计算每条边的msm是点p在边ab上的投影点。

m = (p - a) • (b - a) / |b - a|² * (b - a) + a
s = (p - m) • (c - m)

如果 s 是正数,则 pcab 的同侧。对于每条边重复此测试。如果 p 和对面的顶点在每条边的同侧,则 p 在三角形内。
这种平面分割技术通常使用叉积来完成,但这种方法可能更有效。
对于 |b - a|²,如果无法获得长度平方,则可以使用 (b - a) • (b - a)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接