我需要射线和矩形之间的交点。到目前为止,我一直遵循答案here,但是在对其进行了测试(如下所述)之后,我意识到实现是错误的。

bool checkRayLightIntersection(Vec Origin, Vec Dir) {

    //(-10,20,9) is Hard-code of the light position and we add (5.0f) on X and Z axis to
    //make it an area instead of a vertex
    //"Origin" is the position of the eye. Hard coded: (-25, 8, 5)
    //"Dir" is LightPosition - Origin

    float randX = 5.0f; //in the future it will be random, that's why this name
    float randZ = 5.0f;

    Vec P1 = Vec(-10 - randX, 20, 9 + randZ);
    Vec P2 = Vec(-10 + randX, 20, 9 + randZ);
    Vec P3 = Vec(-10 + randX, 20, 9 - randZ);
    Vec P4 = Vec(-10 - randX, 20, 9 - randZ);

    //the majority of the methods first find out where the ray intersects the
    //plane that the rectangle lies on, Ax + By + Cz + D = 0
    //in our case the equation of that plane is easy (I think) -> D = 20

    float t = -(-Origin.y + 20) / (-Dir.y);
    if (t > 0) {
        Vec hitPoint = Origin + Dir * t;
        Vec V1 = (P2 - P1).norm();
        Vec V3 = (P4 - P3).norm();
        Vec V4 = (hitPoint - P1).norm();
        Vec V5 = (hitPoint - P3).norm();
        float V1dotV4 = V1.dot(V4);
        float V3dotV5 = V3.dot(V5);
        if (V1dotV4 > 0 && V3dotV5 > 0) {
            return true;
        }
    }
    return false;
 }


我的Vec是一个定义如下的结构:

struct Vec {
    double x, y, z;                  // position, also color (r,g,b)
    Vec(double x_ = 0, double y_ = 0, double z_ = 0){ x = x_; y = y_; z = z_; }
    Vec operator+(const Vec &b) const { return Vec(x + b.x, y + b.y, z + b.z); }
    Vec operator-(const Vec &b) const { return Vec(x - b.x, y - b.y, z - b.z); }
    Vec operator-() const { return Vec(-x, -y, -z); }
    Vec operator*(double b) const { return Vec(x*b, y*b, z*b); }
    Vec operator/(double b) const { return Vec(x / b, y / b, z / b); }
    Vec mult(const Vec &b) const { return Vec(x*b.x, y*b.y, z*b.z); }
    Vec& norm(){ return *this = *this * (1 / sqrtf(x*x + y*y + z*z)); }
    double dot(const Vec &b) const { return x*b.x + y*b.y + z*b.z; }
    // cross:
    Vec operator%(Vec&b){ return Vec(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); }
    double max() const { return x>y && x>z ? x : y > z ? y : z; }
};


我测试了该方法。所以我想做的是从原点到应该在矩形外部的点创建光线,例如(-10,20,19),我在Z轴上添加了9,而矩形应该只大了5个单位在每个方向(X,-X,Z,-Z)上。因此,就我而言:

Dir = (-10, 20, 19) - Orig


该方法应返回false时返回true。
您能帮我了解我在做什么错吗?提前致谢。

最佳答案

看来您距离这里很近,但我很好奇V1dotV4V3dotV5的结果。

就是说,由于您的平面方程为-y + 20 = 0(即y = 20且法向[0,-1,0]的平面),因此您似乎正在正确求解t

您可以通过将其重新插入飞机的方程式并检查结果是否为0来验证是否获得了合理的hitPoint

假设hitPoint正确放置在平面上,则好像检查一下hitPoint是否位于矩形内是错误的。您正在使用点积来确保hitPoint在边缘[P1,P2]和[P4,P3]上的投影位于该边缘内。问题是[P1,P2]和[P4,P3]是矩形的相对/平行边缘,因此您的检查没有告诉您hitPoint相对于边缘[P2,P3]和[P4]的位置,P1]。

因为您知道这是一个矩形,所以我认为它足以计算

Vec hitPoint = Origin + Dir * t;
Vec V1 = (P2 - P1).norm();
Vec V2 = (P3 - P2).norm();
Vec V3 = (P4 - P3).norm();
Vec V4 = (P1 - P4).norm();
Vec V5 = (hitPoint - P1).norm();
Vec V6 = (hitPoint - P2).norm();
Vec V7 = (hitPoint - P3).norm();
Vec V8 = (hitPoint - P4).norm();
if (V1.dot(V5) < 0.0) return false;
if (V2.dot(V6) < 0.0) return false;
if (V3.dot(V7) < 0.0) return false;
if (V4.dot(V8) < 0.0) return false;
return true;


编辑我最初的主张是检查两个边的[0,1]范围,但这实际上是不正确的。更新了示例代码以检查所有4条边。

另请注意,您可以通过仅针对矩形的两个垂直边缘检查hitPoint来执行此操作

Vec hitPoint = Origin + Dir * t;
Vec V1 = P2 - P1;
float lengthV1 = V1.length();
Vec normV1 = V1.norm();

Vec V2 = P4 - P1;
float lengthV2 = V2.length();
Vec normV2 = V2.norm();

Vec hitVec = P - P1;
a = normV1.dot(hitVec);
b = normV2.dot(hitVec);
return (0.0f <= a && a <= lengthV1 && 0.0f <= b && b <= lengthV2);

关于c++ - C++中Ray和Rectangle的交集,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36180741/

10-11 18:57