繁体   English   中英

如何做射线平面相交?

[英]How to do ray plane intersection?

如何计算射线和平面之间的交点?

代码

这会产生错误的结果。

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表示射线对象。
ray.direction是方向向量。
ray.origin是原点向量。
rec表示结果对象。
rec.tHit是命中的值。
rec.anyHit是一个布尔值。

我的函数可以访问飞机:
centernormal定义了平面

正如 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;

首先考虑射线平面相交的数学:

通常,光线的参数形式与几何的隐式形式相交。

所以给定形式为 x = a * t + a0, y = b * t + b0, z = c * t + c0;

和形式为:A x * B y * C z + D = 0 的平面;

现在将 x、y 和 z 射线方程代入平面方程,您将得到 t 中的多项式。 然后,您可以为 t 的实际值求解该多项式。 使用这些 t 值,您可以代入射线方程以获得 x、y 和 z 的实际值。 这是在千里马:

在此处输入图片说明

请注意,答案看起来像两点乘积的商! 平面的法线是平面方程 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);
}

执行 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;
}

让初始点p0p = p0 + t*vt >= 0方向向量v参数化地给出射线。

对于法向量n = (a, b, c)和常数d n = (a, b, c)让平面由dot(n, p) + d = 0给出。 如果r是平面上的一个点,则d = - dot(n, r) 完全展开后,平面方程也可以写成ax + by + cz + d = 0

将射线代入平面方程给出:

t = - (dot(n, p) + d) / dot(n, v)

示例实现:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM