OpenGL 中的射线球相交

Posted

技术标签:

【中文标题】OpenGL 中的射线球相交【英文标题】:Ray Sphere Intersections in OpenGL 【发布时间】:2015-12-13 13:46:27 【问题描述】:

我正在尝试在 OpenGL 中使用射线球交点来执行鼠标拾取。我在网上找了几个公式,最后一个是 Stack Exchange 上一位用户建议的:

Ray-Sphere intersection

根据我对这个答案的理解,我正在检查二次方程是否有正根。我真的不在乎相交发生在哪里,只要光线与球体相交即可。我的代码如下,但似乎不起作用。

bool Mesh::useObject(vec3 camera, vec3 direction) 

    // a = (xB-xA)²+(yB-yA)²+(zB-zA)²
    float a = ((direction.v[0] - camera.v[0])*(direction.v[0] - camera.v[0])
        + (direction.v[1] - camera.v[1])*(direction.v[1] - camera.v[1])
        + (direction.v[2] - camera.v[2])*(direction.v[2] - camera.v[2]));

    // b = 2*((xB-xA)(xA-xC)+(yB-yA)(yA-yC)+(zB-zA)(zA-zC))
    float b = 2 * ((direction.v[0] - camera.v[0])*(camera.v[0] - mOrigin.v[0])
        + (direction.v[1] - camera.v[1])*(camera.v[1] - mOrigin.v[1])
        + (direction.v[2] - camera.v[2])*(camera.v[2] - mOrigin.v[2]));

    // c = (xA-xC)²+(yA-yC)²+(zA-zC)²-r²
    float c = ((camera.v[0] - mOrigin.v[0])*(camera.v[0] - mOrigin.v[0])
        + (camera.v[1] - mOrigin.v[1])*(camera.v[1] - mOrigin.v[1])
        + (camera.v[2] - mOrigin.v[2])*(camera.v[2] - mOrigin.v[2])
        - (mRadius)*(mRadius));

    float delta = (b*b) - (4 * a*c);

    if (delta < 0)
        return false;

    else 
        std::cout << "Object " << mMesh << " is at postion (" <<
            mOrigin.v[0] << ", " <<
            mOrigin.v[1] << ", " <<
            mOrigin.v[2] << ")\n" <<
            "Size: " << mRadius << std::endl;
        return true;
    

我的 C++ 技能相当生疏,所以如果这是一种可怕的做法,我深表歉意。此方法采用三个浮点数的两个向量、相机的位置以及相机前面 1 个单位的场景中的点的坐标(我称之为方向)。

当我面对一个对象并按下一个键时,我想获取对象的位置及其半径,但只有当我站在场景中的一个对象上,或者我站得很近时,我才会得到输出到另一个大物体。很明显我的计算有问题(或者更糟糕的是,我的代码),但我无法弄清楚那是什么。 :(

如果您需要更多代码,或者有任何不清楚的地方,请告诉我。这是我对 SO 的第一个问题,所以如果这个问题措辞不当,我很抱歉。

编辑:我不应该使用鼠标坐标作为我的射线上的一个点。稍微修改了我的问题。

【问题讨论】:

您的 fromulas 完全忽略了您的投影矩阵(可能还有模型和视图矩阵)。仅使用 (mouse_x, mouse_y,cam_z+1) 作为方向向量将 a) 得出一个非常奇怪的视野,并且 b) 还完全忽略 x 和 y 中的相机位置以及相机方向。 是的,你是对的,那是我的错。我曾经使用一个物理点,它只是相机的 x 和 y 位置,以及它的 z 位置 + 1,但这不起作用,绝望中我尝试使用鼠标坐标来查看是否会改变任何东西。假设我恢复到其他方法,这段代码应该工作吗? 对不起,这不正确。相机的 x 和 y 位置以及它所面对的任何方向 +1。 这并不重要。您仍然完全忽略投影参数。而且您还忽略了对象的模型转换(如果有)。您需要使用与渲染相同的投影参数unproject 2D 鼠标坐标,以获得有意义的 3D 方向矢量。 为什么在世界空间计算光线时需要投影参数? (假设我现在不使用鼠标坐标)。此外,我的对象的原点已与对象一起转换。 【参考方案1】:

这段代码看起来很乱。检查直线(direction,origin)与球体(centerradius)相交的通用公式应该是:

length(cross(direction, center-origin)) / length(direction) < radius

检查你是否正确实现,也许将一些操作分解成单独的函数。

【讨论】:

以上是关于OpenGL 中的射线球相交的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 3D拾取文章(转)

OpenGL 鼠标在 3D 空间中的位置

具有移动球体的射线球测试的良好加速结构

opengl编程 : 利用鼠标的位置跟踪一条在世界坐标系中的射线

Opengl:尝试绘制线条以可视化鼠标射线投射时出现意外行为

将 android-opengl 上的触摸转换为射线/矢量并检查它是不是击中平面