0

我编写了一个将“屏幕”坐标转换为“视图”坐标的函数。它看起来像这样(C# 中的示例):

Vector2 ScreenToViewCoords(Point p)
{
    return new Vector2(
        _projMatrix.M11 * p.X + _projMatrix.M12 * p.Y + _projMatrix.M14,
        _projMatrix.M21 * p.X + _projMatrix.M22 * p.Y + _projMatrix.M24
    );
}

p是相对于 OpenGL 控件/视口左上角的一个点,以像素为单位。

_projMatrix是我的投影矩阵。

我的渲染函数如下所示:

private void Render()
{
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadMatrix(ref _projMatrix);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadIdentity();

    if (_texture != null)
    {
        _texture.Bind();
        GL.Color3(Color.White);
        GL.Begin(BeginMode.Quads);
        {
            GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
            GL.TexCoord2(0, 1); GL.Vertex2(0, _texture.Height);
            GL.TexCoord2(1, 1); GL.Vertex2(_texture.Width, _texture.Height);
            GL.TexCoord2(1, 0); GL.Vertex2(_texture.Width, 0);
        }
        GL.End();
        _texture.Unbind();
    }

    glControl.SwapBuffers();
}

它使用投影矩阵,并在屏幕上绘制图像,始终位于同一位置:(0,0)到(宽度,高度)。

由于图像是在 1 个视图单元 = 1 个像素处绘制的,所以我希望我的投影矩阵所要做的只是进行一点平移以将图像放置在正确的位置。因此,我认为它看起来像

 1  0  0  0
 0  1  0  0
 0  0  1  0
tx ty  0  1

但它实际上看起来像这样:

(注意:它看起来是旋转的,因为这些是列,而不是行)

那部分已经让我感到困惑,但无论如何,我的数学应该是正确的,除非我忘记了什么?

请注意,渲染功能完全按照预期工作,我只是想将鼠标单击转换为视图坐标。另请注意,这是一个 2D 应用程序,因此并未真正使用 Z 向量(同样,不确定为什么Column2会出现奇怪的情况)。

那么我在这里做错了什么,坐标没有正确输出?

例如,如果我如前所述在 (0,0) 到 (w,h) 处绘制图像,然后单击 700x500 图像的右下角,我希望它输出 699x499 但它出来(0.9959349, -0.9971989)

编辑:找出为什么Z坐标很奇怪。我已经在 -1 和 11 而不是 -1 和 1 之间设置了正交矩阵。然而,这并没有真正改变任何东西,因为 Z 值无关紧要。

Edit2:我现在想到投影矩阵将模型视图转换为屏幕坐标,而我基本上想做相反的事情——我需要反转矩阵吗?这样做会给我更多的像素数字,但乘以它会使我的坐标太大:

4

1 回答 1

1

GL 中的投影矩阵转换为归一化坐标空间,其中 X 和 Y 将介于 -1 和 1 之间(在透视除法之后,在正交投影中可以忽略,因为它只是除以 1)

要获取像素坐标,您需要按视口缩放/偏移,以便 -1 到 1 范围映射到视口中指定的左右宽度和高度。

例如:

screenX = (viewWidth * (normX + 1) / 2) + viewLeft;

要将屏幕坐标转换回视图坐标,请反向执行所有操作 - 将屏幕坐标转换为标准化坐标,然后将它们推入逆变换。

gluProject()并将gluUnproject()为您执行此操作,或者您可以咨询来源。

于 2013-03-03T09:19:33.567 回答