C++ 如何做射线平面相交?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23975555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do ray plane intersection?
提问by Pontus Magnusson
How do I calculate the intersection between a ray and a plane?
如何计算射线和平面之间的交点?
Code
代码
This produces the wrong results.
这会产生错误的结果。
float denom = normal.dot(ray.direction);
if (denom > 0)
{
float t = -((center - ray.origin).dot(normal)) / denom;
if (t >= 0)
{
rec.tHit = t;
rec.anyHit = true;
computeSurfaceHitFields(ray, rec);
return true;
}
}
Parameters
参数
ray
represents the ray object.ray.direction
is the direction vector.ray.origin
is the origin vector.rec
represents the result object.rec.tHit
is the value of the hit.rec.anyHit
is a boolean.
ray
表示射线对象。ray.direction
是方向向量。ray.origin
是原点向量。rec
表示结果对象。rec.tHit
是命中值。rec.anyHit
是一个布尔值。
My function has access to the plane:center
and normal
defines the plane
我的函数可以访问平面:center
并normal
定义平面
回答by Trillian
As wonce commented, you want to also allow the denominator to be negative, otherwise you will miss intersections with the front face of your plane. However, you still want a test to avoid a division by zero, which would indicate the ray being parallel to the plane. You also have a superfluous negation in your computation of t
. Overall, it should look like this:
正如 wonce 评论的那样,您还希望分母为负数,否则您将错过与飞机正面的交叉点。但是,您仍然需要进行测试以避免除以零,这表明光线与平面平行。您在 的计算中也有一个多余的否定t
。总的来说,它应该是这样的:
float denom = normal.dot(ray.direction);
if (abs(denom) > 0.0001f) // your favorite epsilon
{
float t = (center - ray.origin).dot(normal) / denom;
if (t >= 0) return true; // you might want to allow an epsilon here too
}
return false;
回答by vwvan
First consider the math of the ray-plane intersection:
首先考虑射线平面相交的数学:
In general one intersects the parametric form of the ray, with the implicit form of the geometry.
通常,光线的参数形式与几何的隐式形式相交。
So given a ray of the form x = a * t + a0, y = b * t + b0, z = c * t + c0;
所以给定形式为 x = a * t + a0, y = b * t + b0, z = c * t + c0;
and a plane of the form: A x * B y * C z + D = 0;
和形式为:A x * B y * C z + D = 0 的平面;
now substitute the x, y and z ray equations into the plane equation and you will get a polynomial in t. you then solve that polynomial for the real values of t. With those values of t you can back substitute into the ray equation to get the real values of x, y and z. Here it is in Maxima:
现在将 x、y 和 z 射线方程代入平面方程,您将得到 t 中的多项式。然后,您可以为 t 的实际值求解该多项式。使用这些 t 值,您可以代入射线方程以获得 x、y 和 z 的实际值。这是在千里马:
Note that the answer looks like the quotient of two dot products! The normal to a plane is the first three coefficients of the plane equation A, B, and C. You still need D to uniquely determine the plane. Then you code that up in the language of your choice like so:
请注意,答案看起来像两点乘积的商!平面的法线是平面方程 A、B 和 C 的前三个系数。您仍然需要 D 来唯一地确定平面。然后你用你选择的语言编写代码,如下所示:
Point3D intersectRayPlane(Ray ray, Plane plane)
{
Point3D point3D;
// Do the dot products and find t > epsilon that provides intersection.
return (point3D);
}
回答by Bas Smit
implementation of vwvan's answer
执行 vwvan 的答案
Vector3 Intersect(Vector3 planeP, Vector3 planeN, Vector3 rayP, Vector3 rayD)
{
var d = Vector3.Dot(planeP, -planeN);
var t = -(d + rayP.z * planeN.z + rayP.y * planeN.y + rayP.x * planeN.x) / (rayD.z * planeN.z + rayD.y * planeN.y + rayD.x * planeN.x);
return rayP + t * rayD;
}
回答by Mateen Ulhaq
Let the ray be given parametrically by p = p0 + t*v
for initial point p0
and direction vector v
for t >= 0
.
让参射线由下式给出p = p0 + t*v
用于初始点p0
和方向矢量v
为t >= 0
。
Let the plane be given by dot(n, p) + d = 0
for normal vector n = (a, b, c)
and constant d
. If r
is a point on the plane, then d = - dot(n, r)
. Fully expanded, the plane equation may also be written ax + by + cz + d = 0
.
让平面由dot(n, p) + d = 0
法向量n = (a, b, c)
和常数给出d
。如果r
是平面上的一个点,则d = - dot(n, r)
。完全展开后,平面方程也可以写成ax + by + cz + d = 0
。
Substituting the ray into the plane equation gives:
将射线代入平面方程给出:
t = - (dot(n, p) + d) / dot(n, v)
Example implementation:
示例实现:
std::optional<vec3> intersectRayWithPlane(
vec3 p, vec3 v, // ray
vec3 n, float d // plane
) {
float denom = dot(n, v);
// Prevent divide by zero:
if (abs(denom) <= 1e-4f)
return std::nullopt;
// If you want to ensure the ray reflects off only
// the "top" half of the plane, use this instead:
if (-denom <= 1e-4f)
return std::nullopt;
float t = -(dot(n, p) + d) / dot(n, v);
// Use pointy end of the ray.
// It is technically correct to compare t < 0,
// but that may be undesirable in a raytracer.
if (t <= 1e-4)
return std::nullopt;
return p + t * v;
}