C# 如何在3D中选择平面边和三角形边之间的两个正确交点之一?

C# 如何在3D中选择平面边和三角形边之间的两个正确交点之一?,c#,vector,3d,geometry,intersection,C#,Vector,3d,Geometry,Intersection,我在3D空间的某个地方有一条直线(a,B)和一个三角形(P0,P1,P2)。换句话说,三角形有三个点([x,y,z]),直线有两个点(也是[x,y,z])。直线的一点位于三角形内(A或B)。主要目标是在屏幕上找到三角形边上的交点,该三角形边构成直线(A,B)的一部分 我所做的: 1.从线起点(A)、线终点(B)和摄像机位置计算平面法线: Vector3 Normal=Vector3.Cross(A-cameraPos,B-cameraPos); 2.通过检查三角形的每条边找到两个交点: boo

我在3D空间的某个地方有一条直线(
a
B
)和一个三角形(
P0
P1
P2
)。换句话说,三角形有三个点([x,y,z]),直线有两个点(也是[x,y,z])。直线的一点位于三角形内(
A
B
)。主要目标是在屏幕上找到三角形边上的交点,该三角形边构成直线(
A
B
)的一部分

我所做的:

1.从线起点(
A
)、线终点(
B
)和摄像机位置计算平面法线:

Vector3 Normal=Vector3.Cross(A-cameraPos,B-cameraPos);
2.通过检查三角形的每条边找到两个交点:

bool IsPlaneIntersectLine(向量3法线、向量3 A、向量3 B、向量3边点1、向量3边点2、外向量3交点)
{
浮点点积=矢量3.Dot(正常,(边点1-边点2));
如果(dotProduct==0f)
返回false;
float dot1=Vector3.Dot(正常,(A-边点2));
浮动距离=点1/点积;
如果(距离>1f | |距离<0f)
返回false;
交叉点=边点2+距离*(边点1-边点2);
返回true;
}
Vector3相交1、相交2、相交3;
布尔isEdge1Intersected=IsPlaneIntersectLine(法线、A、B、三角形.P0、三角形.P1、外交点1);
布尔isEdge2Intersected=IsPlaneIntersectLine(法线、A、B、triangle.P1、triangle.P2、out intersection2);
布尔isEdge3Intersected=平面相交线(法线、A、B、三角形.P2、三角形.P0、外相交3);
因此,我有两个交叉点,但只有一个是正确的-交叉点,即线路的一部分(
a
B
在屏幕上。此外,我还有一些限制-我无法将这些点转换为屏幕空间进行检查-两个交点中的哪一个位于
A
B
之间

我还尝试检查线向量和相交向量之间的点积:

float-dot=Vector3.dot((交点-A)、(B-A));
如果(点<0f)
{
返回false;
}
但有些三角形/边不适合这种情况


如何在构成屏幕上直线(
A
B
)一部分的三角形边上找到一个交点?

下面给出的答案是游戏开发人员的答案,而不是几何专业的答案,所以这会让大多数数学爱好者感到畏缩,但通常应该是可行的

由于三角形是平面的,并且您已经计算了平面法线,因此可以创建一个变换矩阵来旋转三角形,使其法线笔直向上,并将其中心平移到[0,0,0]。(我无法在脑海中解释创建这个矩阵的数学原理,但有许多内置了这种逻辑的开源库,基本上是一个反向“查看”矩阵)。这实际上是一个从世界到局部的空间矩阵

一旦你有了这个矩阵,你就可以将它应用到直线上的两点上,将其移动到局部空间,然后你就有了一个非常简单的任务,即确定直线与XZ轴平面相交的位置(即求解Y等于零的位置)。虽然这里所有的东西都是临时二维的,但也可以使用重心坐标来检查交点是否在三角形中、边界上或外部


一旦你在局部空间中找到了答案点,通过矩阵的倒数变换它,将其移回世界空间,你就应该这样做。

如果你想要一条直线和最多两条边的二维交点,如屏幕上所示,那么你需要先计算投影坐标。
有关详细信息,请搜索学习变换的任何好教程(通过使用4x4矩阵)。确保理解三种转换:模型、视图和投影。 一旦有了二维数据(在投影后消除“深度”坐标),问题就减少到测试三个二维直线交点


如果您选择了一个三维交集(原始数据,无变换),则搜索线平面交集(三角形平面)。一旦得到交点(如果有),计算从该点到每条边的距离。

正如我在我的文章中描述的一种方法,属于更通用的算法,检查这种特殊情况的一种直接方法是形成两个叉积向量

V1=Vector3.Cross((A-cameraPos),(Cross-cameraPos))

V2=Vector3.交叉点((交叉点-摄像机)、(B-摄像机))

这两个向量垂直于平面
(cameraPos,A,B)
,因此位于一条公共线上。如果两者都指向同一方向,那么当您的视线从点
A
向点
B
旋转时,您将看到第一个点
A
,然后是点
交叉点
,然后是点
B
。但是,如果向量
V1
V2
指向相反的方向,则您将看不到点A和点B之间的点交点。因此,为了解决您的问题,我希望使用以下算法来完成此工作:

V1 =  Vector3.Cross((A - cameraPos), (Intersection - cameraPos));
V2 =  Vector3.Cross((Intersection - cameraPos), (B - cameraPos));
dot = Vector3.Dot(V1, V2);

if dot < 0f
{
   return false
} 
V1=Vector3.Cross((A-cameraPos),(Cross-cameraPos));
V2=矢量3.交叉点((交叉点-摄像机),(B-摄像机));
点=矢量3.点(V1,V2);
如果点<0f
{
返回错误
} 
注意,所有这些算法大多适用于可见三角形,因此对于不可见的三角形,需要小心。此外,如果A和B在同一个三角形中,这些算法会遇到异常。如果
A
已经在一个tr上