我正在尝试实现线段和平面相交测试,该测试将根据它是否与平面相交返回 true 或 false。它还将返回线相交平面上的接触点,如果线不相交,如果线段是一条射线,该函数仍应返回交点。我使用了 Christer Ericson 的实时碰撞检测中的信息和代码,但我认为我没有正确实现它。
我使用的平面来自三角形的法线和顶点。在平面上找到交点的位置就是我想要的,不管它是否位于我用来导出平面的三角形上。
函数的参数如下:
contact = the contact point on the plane, this is what i want calculated
ray = B - A, simply the line from A to B
rayOrigin = A, the origin of the line segement
normal = normal of the plane (normal of a triangle)
coord = a point on the plane (vertice of a triangle)
这是我使用的代码:
bool linePlaneIntersection(Vector& contact, Vector ray, Vector rayOrigin, Vector normal, Vector coord) {
// calculate plane
float d = Dot(normal, coord);
if (Dot(normal, ray)) {
return false; // avoid divide by zero
}
// Compute the t value for the directed line ray intersecting the plane
float t = (d - Dot(normal, rayOrigin)) / Dot(normal, ray);
// scale the ray by t
Vector newRay = ray * t;
// calc contact point
contact = rayOrigin + newRay;
if (t >= 0.0f && t <= 1.0f) {
return true; // line intersects plane
}
return false; // line does not
}
在我的测试中,它永远不会返回 true...有什么想法吗?
最佳答案
我正在回答这个问题,因为当被要求提供光线相交的 C++ 示例时,它首先出现在 Google 上 :)
代码总是返回 false 因为你在这里输入了 if :
if (Dot(normal, ray)) {
return false; // avoid divide by zero
}
只有当 vector 垂直时点积才为零,这是您要避免的情况(无交集),非零数在 C 中为真。
因此解决方案是取反 ( ! ) 或做 Dot(...) == 0。
在所有其他情况下都会有一个交叉点。
关于交集计算: 平面的所有点 X 都遵循方程
Dot(N, X) = d
其中 N 是法线,d 可以通过将平面的已知点放入方程中找到。
float d = Dot(normal, coord);
在射线上,一条线的所有点s 都可以表示为一个点p 和一个给出方向的 vector D :
s = p + x*D
所以如果我们搜索哪个x s在平面上,我们有
Dot(N, s) = d
Dot(N, p + x*D) = d
点积a.b是transpose(a)*b。
令transpose(N)为Nt .
Nt*(p + x*D) = d
Nt*p + Nt*D*x = d (x scalar)
x = (d - Nt*p) / (Nt*D)
x = (d - Dot(N, p)) / Dot(N, D)
这给了我们:
float x = (d - Dot(normal, rayOrigin)) / Dot(normal, ray);
我们现在可以通过将 x 放入直线方程 来获得交点
s = p + x*D
Vector intersection = rayOrigin + x*ray;
上面的代码更新了:
bool linePlaneIntersection(Vector& contact, Vector ray, Vector rayOrigin,
Vector normal, Vector coord) {
// get d value
float d = Dot(normal, coord);<br/>
if (Dot(normal, ray) == 0) {
return false; // No intersection, the line is parallel to the plane
}<br/>
// Compute the X value for the directed line ray intersecting the plane
float x = (d - Dot(normal, rayOrigin)) / Dot(normal, ray);<br/>
// output contact point
*contact = rayOrigin + normalize(ray)*x; //Make sure your ray vector is normalized
return true;
}
旁白 1:
d 值是什么意思?
对于两个 vector a 和 b,点积实际上返回一个 vector 在另一个 vector 上的正交投影乘以另一个 vector 的长度。
但是如果 a 被归一化(长度 = 1),那么 Dot(a, b) 就是 b 在 上的投影长度>一个。对于我们的平面,d 为我们提供了平面上所有点在法线方向上到原点的方向距离(a 是法线)。然后我们可以通过比较投影在法线(点积)上的长度来判断一个点是否在这个平面上。
旁白 2:
如何检查射线是否与三角形相交? (用于光线追踪)
为了测试光线是否进入由 3 个顶点给出的三角形,您首先必须执行此处显示的操作,获取与三角形形成的平面的交点。
下一步是查看该点是否位于三角形内。这可以使用重心坐标来实现,重心坐标将平面中的一个点表示为其中三个点的组合。参见 Barycentric Coordinates and converting from Cartesian coordinates
关于c++ - 3D线段与平面相交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7168484/