在三维空间中,射线与正方形/矩形的相交问题

5
嗨,您正在制作一款游戏,并且正在寻找在3D空间中仅针对正方形或矩形的光线相交。已经在网上搜索了许多解决方案,但是没有一种我能够理解的方法。我有一个2D的直线和线段相交脚本,但我无法弄清楚如何将其转换为3D。
重要的是它与正方形或矩形的哪一侧相交并不重要,但必须能够检索交点向量,以便稍后可以测试距离,以查看它是否发生在同一光线交点之前或之后。
非常感谢任何使用Python或其他类似脚本语言的示例。
编辑:不知道如何修改2D以显示示例,但已经创建了一个新的并发布了两个版本。
//this is the exaple it test a ray onto a plane then look to se if that point is in the rectangle and saves it to test for distanse later
list Faces; //triangle faces
list Points; //

vector FindPoint(){
    //calcute the point of intersection onto the plane and returns it
    //if it can intersect
    //else return ZERO_VECTOR
}

integer point-in-quadrilateral(){
    //return 1 if the point is in the rectangular on the plane
    //else return 0
}

default{

    state_entry(){
        integer n = (Faces != []); //return number of elements
        integer x = 0;
        while(x < n){
            vector intersection = FindPoint( FromList(Faces, x) ); //take     out a element and runs it trough the function
            if(intersection != ZERO_VECTOR){
                integer test = point-in-quadrilateral( FromList(Faces,     x) ); //find out if the point is in rectangular
                if(test == 1){ //if so
                    Points += intersection; //save the point
                }
            }
            ++x;
        }

        float first; //the distanse to the box intersection
        integer l = (Points != []);
        integer d;
        while(d < l){
            if(Dist( FromList(Points, d) ) < first) //if the new distanse     is less then first
                return 0; //then end script
            ++d;
        }
    }

}


//this is the 2D version
vector lineIntersection(vector one, vector two, vector three, vector four){
float bx = two.x - one.x;
float by = two.y - one.y;
float dx = four.x - three.x;
float dy = four.y - three.y; 
float b_dot_d_perp = bx*dy - by*dx;
if(b_dot_d_perp == 0.0) {
    return ZERO_VECTOR;
}
float cx = three.x-one.x; 
float cy = three.y-one.y;
float t = (cx*dy - cy*dx) / b_dot_d_perp; 
if(LineSeg){ //if true tests for line segment
    if((t < 0.0) || (t > 1.0)){
        return ZERO_VECTOR;
    }
    float u = (cx * by - cy * bx) / b_dot_d_perp;
    if((u < 0.0) || (u > 1.0)) {
        return ZERO_VECTOR;
    }
}

return <one.x+t*bx, one.y+t*by, 0.0>; 

}

3个回答

17
解决方案很简单,当您使用一个点(=向量)和一个方向向量定义射线,以及使用一个点(=向量)和代表两个边的两个向量来定义矩形时。假设射线被定义为 R0 + t * D,其中R0是射线的起点,D是表示其方向的单位向量,t是其长度。 矩形可以用一个角点 P0 和两个向量 S1 和 S2 来表示,这些向量应表示它们的边(其长度等于边的长度)。你还需要另一个向量 N,它垂直于它的表面,并等于S1和S2的叉积沿着其单位向量。
现在,假设射线与矩形相交于 P。那么,射线的方向 D 必须与法向量 N 成非零角度。这可以通过检查 D·N < 0 来验证。
要找到交点,请假设 P = R0 + a * D(该点必须在射线上)。现在需要找到 a 的值。找出向量 P0P。这必须垂直于 N,这意味着 P0P·N = 0,这将缩小为 a = ((P0 - R0)·N) / (D·N)。
现在您需要检查点是否在矩形内。为此,请沿着 S1 取 P0P 的投影 Q1,以及沿着 S2 取 P0P 的投影 Q2。点在内部的条件是 0 <= |Q1| <= |S1| 和 0 <= |Q2| <= |S2|。
该方法适用于任何类型的平行四边形,不仅适用于矩形。[更新:在平行四边形的情况下(包括矩形),应沿另一侧取得其投影,而不仅仅是垂直线(引用最后一段中的“沿着 S1 取 Q1 投影,以及沿着 S2 取 Q2 投影”)。这就像使用一个坐标系,其中轴不相互垂直。]

1
感谢您的好文章。您的文章帮助我们确定问题并解决了它。 - TeaWave
太棒了,谢谢! - Mikaelblomkvistsson
提到的绘图,使用 P0 替代 P:http://imgur.com/a/Dt6ZvIV - Smartskaft2
2
你从 P0P.N = 0 跳跃到了 a = ((P0 - R).N) / (D.N),能否详细说明一下? - Post169
1
还有一件事。如果 a < 0,则没有交点。 - 김선달
显示剩余4条评论

3

创建R3中一条直线的向量方程,然后解出该直线与要测试的矩形所在平面的交点。之后,测试该解点是否在边界范围内即可。

解的参数t可以通过以下公式得到:

t = (a * (x0 - rx) + b * (y0 - ry) + c * (x0 - rz)) / (a * vx + b * vy + c * vz)

场所:

a(x - x0) + b(y - y0) + c(z - z0) = 0

这是你的矩形所在平面的方程。

以及:

<x, y, z> = <rx + vx * t, ry + vy * t, rz + vz * t>

这是所讨论的直线的向量方程。

请注意:

<rx, ry, rz>

是向量方程的初始点,而

<vx, vy, vz>

上述方程的方向向量为。

之后,将参数 t 带入您的向量方程中,即可得到要测试距离的点。

enter image description here


谢谢您的回复。您能解释一下其中的一些部分吗?"x0 y0 z0"是将其等化器,使第二个方程等于零吗?如果是这样,如何计算它们每个的值? - TeaWave
基本上是这样。x0,y0和z0是某个点(可以是任何点),它位于与您的矩形相同平面上。至于方程中的x、y和z,您应该插入上面列出的线性方程(r_ + v_ * t)的值。您能否更具体地说明您计划如何编写代码?也许您可以提供一个您已经解决的2D版本的示例?这样我可能会更好地解释。 - Joel Cornett
已经编辑了主贴以提供示例和2D版本。我们进行了更多的发现,并且想知道a、b和c是否是平面的单位向量?x0、y0和z0是否是线性方程?我们运行了多个组合,但无法使其等于零。 - TeaWave
我编辑了帖子并加入了一张图片以便澄清。无论如何,我给出的第二个方程并不重要。你真正想做的是把数值代入第一个方程中得到参数“t”。然后,你会把“t”代入线(也就是你正在追踪的光线——顺便说一下,那是第三个方程)的向量方程中。 - Joel Cornett
感谢您一直以来的好帮助。现在我已经弄清楚了:) - TeaWave

0

你没有说明在三维空间中的正方形/矩形是否与坐标轴对齐。

假设三维矩形R在空间中是任意定向的,这里提供一种方法。

首先,将你的射线r与包含R的平面相交。这可以通过要求一个比例因子s来实现,将其乘以r并将其放置在R的平面上,并解决s。这给你一个点p在平面上。现在将平面和Rp投影到其中一个坐标平面{xyyzzx}上。你只需要避免垂直于平面法向量的投影,这总是可能的。然后在投影平面中解决点-四边形问题。

开始之前,请检查你的线段是否位于R的三维平面内,如果是,请单独处理。


感谢您的回复。在三维空间中,正方形和矩形可以以任意角度进行旋转。所以如果我理解正确的话,您在文中写到的“首先将射线r与包含R的平面相交。这可以通过要求一个比例因子s来将r乘以它,并放置在R的平面上,并解出s的值”是Joel Carnett提供的解决方案,然后我使用从那里得到的交点向量,并与四边形内的点进行判断,以确定其是否在边界内。 - TeaWave
是的,你理解了。我似乎回答得太高深了,但 Joel 本质上是在用方程式表达我用文学语言描述的内容。 - Joseph O'Rourke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接