射线平面交叉怎么办?

Pon*_*son 14 c++ raytracing

如何计算光线与平面之间的交点?我一直在访问我能找到的每个可能的网站,这是我迄今为止取得的成就:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用:s
我的函数输入是:
ray:包含原点和方向.
rec:用于存储命中信息的容器类(bool,t等)

我的函数可以访问平面:
点:定义平面
法线的点:定义平面的法线

Tri*_*ian 19

正如你所评论的那样,你也希望分母为负数,否则你会错过与飞机前面的交叉点.但是,您仍然希望测试避免被零除,这表示光线与平面平行.你的计算中也有一个多余的否定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;
Run Code Online (Sandbox Code Playgroud)

  • 什么是中心? (13认同)
  • @ Duckdoom5:我显然是在谈论C++,因为这个问题被标记为C++.我假设你在谈论`std :: abs()`(它有不同的重载)而不是`abs()`(它只处理整数).由于答案包含`abs()`而不是`std :: abs()`并且不使用`using`指令,我认为这是一个错误.有关更多信息,请参见此处:http://stackoverflow.com/questions/21392627/abs-vs-stdabs-what-does-the-reference-say (4认同)

vwv*_*van 8

首先考虑光线平面交点的数学运算:

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

因此,给定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);
}
Run Code Online (Sandbox Code Playgroud)

  • “t =”旁边的“-”符号几乎看不见。 (2认同)

Mat*_*haq 6

数学

定义:

  • 令射线参数化地给出为q = p + t*v的初始点p和 的方向向量。vt >= 0

  • r令平面为满足dot(n, r) + d = 0法向量n = (a, b, c)和常数方程的点集d。完全展开后,平面方程也可以写成熟悉的形式ax + by + cz + d = 0

当满足平面方程时,光线与q平面相交。代入,我们有:

d = -dot(n, q)
  = -dot(n, p + t * v)
  = -dot(n, p) + t * dot(n, v)
Run Code Online (Sandbox Code Playgroud)

重新排列:

t = -(dot(n, p) + d) / dot(n, v)
Run Code Online (Sandbox Code Playgroud)

该值t可用于通过将其插回 来确定交集p + t*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;
}
Run Code Online (Sandbox Code Playgroud)