我正面临着与三角形边缘相交的问题。实际上,我正在尝试使用鼠标选择/交叉网格的三角形,顶点,边缘。所以我从鼠标当前位置制作了光线,然后我将它与网格元素(如三角形/多边形,顶点,边缘等)相交以使用它。基本上,3D建模的东西。与三角形相交很简单有趣。顶点部分很棘手。
但现在,我不知道如何用三角形边相交/拾取。我的意思是我在与鼠标射线相交时如何对待它们?首先,我认为它们可以像3D线一样对待。但最终未能做到Ray和the 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?
}
}
}
}
所以我被困在这里,真的需要一些帮助。非常感谢任何想法,算法或小帮助。
答案 0 :(得分:1)
请查看本页末尾的算法以及本网站提供的所有算法:http://geomalgorithms.com/a05-_intersect-1.html
答案 1 :(得分:1)
在您的情况下,在3D空间中找到三角形和光线之间的交点的问题可以归结为在2D空间(平面)中以三角形查找点位置(INSIDE,OUTSIDE,ON BOUNDARY)。您应该做的就是在屏幕平面上投影三角形,在边缘找到交叉点并在边缘上执行反向投影。点的位置是鼠标的位置。唯一的问题是处理退化情况,如将三角形映射到线段。但我认为这不会有问题,因为这种情况很容易应对。
答案 2 :(得分:1)
第一种方法是将边缘(和光线)正交投影到垂直于光线的平面,然后计算投影光线到投影边缘的距离。
即,首先确定与光线正交的两个正交矢量rdir1, rdir2
。
然后你计算你的光线(它的基点)到这个平面的投影,这将产生一个2d点rp
。
然后通过简单地应用点积来将边缘投影到该平面:
pv1 = new Vector2(DotProduct(v1, rdir1), DotProduct(v1, rdir2))
pv2 = new Vector2(DotProduct(v2, rdir1), DotProduct(v2, rdir2))
现在,您可以计算从第2行pv1, pv2
到点rp
的距离。
如果边缘的方向取自视图矩阵的“向前”方向,则与其正交的两个向量将是视图矩阵的左右向量。
执行上述配方将产生类似于将边缘投影到屏幕的效果。因此,您也可以将边缘投影到屏幕并使用这些坐标。
答案 3 :(得分:0)
首先,两个几何对象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}
。 (不要担心你问过一条光线,一条线就是你想要的。)
现在计算距离归结为找到合适的t
和s
,使SquareEuclideanLength(v1 + t*(v2-v1) - p - s*d)
最小,然后计算EuclideanLength(v1 + t*(v2-v1) - p - s*d)
以获得真实距离。
要解决这个问题,我们需要一些解析几何。由于d
不为零,我们可以将每个向量v
写为与d
正交的部分和d
的倍数的部分之和:{ {1}}。对于这种“正交分解”,它始终保持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
,使得正确的加数为0! (请记住,s
,Mv1
,...是Mv2
的倍数。)
因此,为了找到最小值,您只需要找到上述地图d
,O
,然后找到最小化器M
。
假设t
已归一化,这些实际上由d
和Ov := CrossProduct(v, d)
提供,但请相信我,如果Mv := DotProduct(v, d)*d
未规范化,这也有效。< / p>
现在找到距离的方法是:找到最小化的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))
和等于0来解决。
所以这个等式的最小化是
t
使用此t = -Dot(Cross(v1 - p, d), Cross(v2 - v1, d))/SquareEuclideanLength(Cross(v2 - v1, d))
计算t
,线段A上距离线B最近的点,您可以将其插入点线距离算法中以查找所需的距离。
我希望这可以帮到你!