How to do ray plane intersection?

后端 未结 4 449
旧巷少年郎
旧巷少年郎 2020-12-08 21:26

How do I calculate the intersection between a ray and a plane?

Code

This produces the wrong results.

float denom = normal.dot(ray.direction         


        
相关标签:
4条回答
  • 2020-12-08 21:47

    Let the ray be given parametrically by p = p0 + t*v for initial point p0 and direction vector v for 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.

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 21:57

    implementation of vwvan's answer

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 22:02

    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:

    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;
    
    0 讨论(0)
  • 2020-12-08 22:03

    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;

    and a plane of the form: 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:

    enter image description here

    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:

    Point3D intersectRayPlane(Ray ray, Plane plane)
    {
        Point3D point3D;
    
        //  Do the dot products and find t > epsilon that provides intersection.
    
    
        return (point3D);
    }
    
    0 讨论(0)
提交回复
热议问题