[英]How to do ray plane intersection?
How do I calculate the intersection between a ray and a plane?如何计算射线和平面之间的交点?
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;
}
}
ray
represents the ray object. ray
表示射线对象。
ray.direction
is the direction vector. ray.direction
是方向向量。
ray.origin
is the origin vector. ray.origin
是原点向量。
rec
represents the result object. rec
表示结果对象。
rec.tHit
is the value of the hit. rec.tHit
是命中的值。
rec.anyHit
is a boolean. rec.anyHit
是一个布尔值。
My function has access to the plane:我的函数可以访问飞机:
center
and normal
defines the plane center
和normal
定义了平面
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.正如 wonce 评论的那样,您还希望分母为负数,否则您将错过与飞机正面的交叉点。 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
.您在
t
的计算中也有一个多余的否定。 Overall, it should look like this:总的来说,它应该是这样的:
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;
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.现在将 x、y 和 z 射线方程代入平面方程,您将得到 t 中的多项式。 you then solve that polynomial for the real values of t.
然后,您可以为 t 的实际值求解该多项式。 With those values of t you can back substitute into the ray equation to get the real values of x, y and z.
使用这些 t 值,您可以代入射线方程以获得 x、y 和 z 的实际值。 Here it is in Maxima:
这是在千里马:
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.
平面的法线是平面方程 A、B 和 C 的前三个系数。您仍然需要 D 来唯一地确定平面。 Then you code that up in the language of your choice like so:
然后你用你选择的语言编写代码,如下所示:
Point3D intersectRayPlane(Ray ray, Plane plane)
{
Point3D point3D;
// Do the dot products and find t > epsilon that provides intersection.
return (point3D);
}
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;
}
Let the ray be given parametrically by p = p0 + t*v
for initial point p0
and direction vector v
for t >= 0
.让初始点
p0
的p = p0 + t*v
和t >= 0
方向向量v
参数化地给出射线。
Let the plane be given by dot(n, p) + d = 0
for normal vector n = (a, b, c)
and constant d
.对于法向量
n = (a, b, c)
和常数d
n = (a, b, c)
让平面由dot(n, p) + d = 0
给出。 If r
is a point on the plane, then d = - dot(n, r)
.如果
r
是平面上的一个点,则d = - dot(n, r)
。 Fully expanded, the plane equation may also be written ax + by + cz + d = 0
.完全展开后,平面方程也可以写成
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.