c# - 如何在 3D 中选择平面和三角形边缘之间的两个正确交点之一?
问题描述
我在 3D 空间的某处有一条线( A
, B
)和一个三角形(P0
, P1
, )。P2
换句话说,三角形有 3 个点(每个 [x,y,z]),直线有两个点(也有 [x,y,z])。线的一点位于三角形(A
或B
)内。主要目标是找到三角形边缘上的交点,该交点在屏幕上构成线 ( 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
)的一部分。我也有限制 - 我无法将此点转换为屏幕空间以进行检查 - 两个交点中的哪一个在和之间。A
B
我还尝试检查线向量和相交向量之间的点积:
float dot = Vector3.Dot((Intersection - A), (B - A));
if (dot < 0f)
{
return false;
}
但是有些三角形/边缘不适合这种情况。
如何在三角形边缘上找到一个交点,该交点构成屏幕上线( A
, )的一部分?B
解决方案
正如我在之前的回答中已经描述的一种方法,与更通用的算法有关,检查这种特殊情况的一种直接方法是形成两个叉积向量
V1 = Vector3.Cross((A - cameraPos), (Intersection - cameraPos))
V2 = Vector3.Cross((Intersection - cameraPos), (B - cameraPos))
这两个向量垂直于平面(cameraPos, A, B)
,因此位于一条公共线上。如果它们都指向同一个方向,那么当你cameraPos
从一个点开始旋转你的视线时,你会看到第一个点,然后是点,然后是点。但是,如果向量和指向相反的方向,那么您将看不到点 A 和 B 之间的交点。因此,为了解决您的问题,我希望以下算法可以完成这项工作:A
B
A
Intersection
B
V1
V2
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 步。
推荐阅读
- jenkins - 在 Jenkinsfile 中引用 curl 命令
- python - 如何将错误消息添加到 API 调用不和谐 python
- javascript - ReferenceError: targetsheetByName 未定义 // GoogleSheets 脚本
- react-native - 在 Telegram 上反应原生共享 base64 图像
- ipv6 - RFC 推荐的 C 中 IPv6 地址和 inet_ntop 的表示形式
- c++ - 不同变量类型的向量编译器错误
- swiftui - 为什么这个自定义形状会占据整个垂直空间?
- r - 合并 R 中的 df 并将列从 df 2 - 12 重命名为 df 1 的列名
- python - 获取列表上的操作作为熊猫中包含列表或字符串的新列
- javascript - 使用来自另一个函数的请求选项调用函数始终为空