【问题标题】:Why aren't my view coordinates coming out correctly?为什么我的视图坐标没有正确显示?
【发布时间】:2013-03-03 06:35:17
【问题描述】:

我编写了一个将“屏幕”坐标转换为“视图”坐标的函数。它看起来像这样(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) 到 (width,height)。

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

【问题讨论】:

    标签: opengl graphics coordinates


    【解决方案1】:

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

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

    例如:

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

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

    gluProject()gluUnproject() 会为你做这件事,或者你可以查阅源代码。

    【讨论】:

    • “视口”是什么意思?我的视口刚刚设置为 (0,0,winWidth,winHeight)。将坐标乘以宽度和高度并不能解决这个问题——你会注意到 Y 坐标甚至是负数(因为我希望 0,0 位于左上角)——应该在某处扭转这一点。跨度>
    • 你不能只是乘法——你需要偏移使得 -1 -> 1 范围映射到 0 -> 1。你为什么不直接使用 gluProject() / gluUnproject() ?
    • 我不知道gluUnproject 并且我使用的库没有它。但是,我确实找到了一个似乎可行的实现。甜!
    猜你喜欢
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    相关资源
    最近更新 更多