从相机投影线

Projecting line from camera

我正在尝试将视口点击转换为对象的世界位置。

如果我只想在用户点击 canvas:

void Canvas::getClickPosition(int x, int y, Vector3d(&out)[2]) const
{
    Vector4d point4d[2];
    Vector2d point2d(x, y);
    int w = canvas.width();
    int h = canvas.height();
    Matrix4d model = m_world * m_camera;

    for (int i = 0; i < 2; ++i) {
        Vector4d sw(point2d.x() / (0.5 * w) - 1,
            point2d.y() / (0.5* h) - 1, i * 1, 1);

        point4d[i] = (m_proj * model).inverse() * sw;
        out[i] = point4d.block<1, 3>(0, 0);
    }
}

预期的行为是通过这个简单的代码实现的。

当我尝试实际制作一条在用户首次单击时看起来像 一个像素 的线时,问题就出现了。在相机朝任何方向旋转之前,它应该看起来像是从相机中完美拍摄的,并且它具有任何长度(无关紧要)。

我尝试了显而易见的方法:

Vector4d sw(point2d.x() / (0.5 * w) - 1,
    point2d.y() / (0.5* h) - 1, 1, 1); // Z is now 1 instead of 0.

正如你们大多数人所预料的那样,结果是一条在屏幕中央追寻 消失点 的线。因此,我点击离中心越远,线条偏离预期方向的幅度就越大。

无论在屏幕的哪个位置,如何使一条线从点击的角度显示为一个点?

编辑:为了更清楚起见,我试图画出这样的线条:

    glBegin(GL_LINES);
    line.p1 = m_proj * (m_world * m_camera) * line.p1;
    line.p2 = m_proj * (m_world * m_camera) * line.p2;

    glVertex3f(line.p1.x(), line.p1.y(), line.p1.z());
    glVertex3f(line.p2.x(), line.p2.y(), line.p2.z());
    glEnd();

您的初步尝试实际上非常接近。你唯一缺少的是透视鸿沟:

out[i] = point4d.block<1, 3>(0, 0) / point4d.w();

根据您的投影矩阵,您可能还需要为近平面指定 -1 的 z 值,而不是 0

是的,您的矩阵顺序 projection * model * view 看起来很奇怪。但是只要您在两个过程中保持相同的顺序,您应该会得到一致的结果。

确保 window 坐标系的 y 轴指向上方。否则,您将得到反映在水平中线的结果。