首页 > 解决方案 > 如何在 3D 中选择平面和三角形边缘之间的两个正确交点之一?

问题描述

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

我所做的:

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

    Vector3 Normal = Vector3.Cross(A - cameraPos, B - cameraPos);

2.通过检查三角形的每条边找到两个交点:

    bool IsPlaneIntersectLine(Vector3 Normal, Vector3 A, Vector3 B, Vector3 EdgePoint1, Vector3 EdgePoint2, out Vector3 Intersection)
    {
        float dotProduct = Vector3.Dot(Normal, (EdgePoint1 - EdgePoint2));
        if (dotProduct == 0f)
            return false;
        float dot1 = Vector3.Dot(Normal, (A - EdgePoint2));
        float distance = dot1 / dotProduct;
        if (distance > 1f || distance < 0f)
            return false;
        Intersection = EdgePoint2 + distance * (EdgePoint1 - EdgePoint2);
        return true;
    }
    Vector3 intersection1, intersection2, intersection3;
    bool isEdge1Intersected = IsPlaneIntersectLine(Normal, A, B, triangle.P0, triangle.P1, out intersection1);
    bool isEdge2Intersected = IsPlaneIntersectLine(Normal, A, B, triangle.P1, triangle.P2, out intersection2);
    bool isEdge3Intersected = IsPlaneIntersectLine(Normal, A, B, triangle.P2, triangle.P0, out intersection3);

结果我有两个交叉点,但只有一个是正确的 - 交叉点,即屏幕上线( A, B)的一部分。我也有限制 - 我无法将此点转换为屏幕空间以进行检查 - 两个交点中的哪一个在和之间。AB

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

    float dot = Vector3.Dot((Intersection - A), (B - A));
    if (dot < 0f)
    {
        return false;
    }

但是有些三角形/边缘不适合这种情况。

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

标签: c#vector3dgeometryintersection

解决方案


正如我在之前的回答中已经描述的一种方法,与更通用的算法有关,检查这种特殊情况的一种直接方法是形成两个叉积向量

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

V2 = Vector3.Cross((Intersection - cameraPos), (B - cameraPos))

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

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

if dot < 0f
{
   return false
} 

需要注意的是,所有这些算法主要适用于可见三角形,因此对于不可见的三角形,需要小心。此外,如果 A 和 B 在同一个三角形中,这些算法会遇到异常。如果A已经在一个三角形的边缘,那么这个修复是不必要的,我认为你可以直接从通用算法进入第 3 步。


推荐阅读