屏幕坐标到2D世界

时间:2013-12-07 11:27:43

标签: vb.net opengl math

这更像是一种肮脏的本性,但无论如何。我需要能够检测到在OpenGl中以四边形显示的图像中单击的位置。四边形的尺寸为5000x5000,渲染为0,0。从我所看到的,这是从窗口中间呈现的。这会在轴的左下角呈现四边形。为了解决这个问题,而不是改变四边形的顶点,因为我需要平移以便在绘制四边形之前进行变换。

因此,为了使四边形在启动时居中,我按GL.Translate(-2500,-2500),0)进行平移。

现在鼠标坐标相对于窗口的左上角,所以我将它们分成一小部分,例如Mouse.X / Width Mouse.Y / Height

这就是iffy的地方。我知道我需要乘以5000,但我还需要以某种方式加入平底锅。

我不确定这是否重要,但这就是我的Ortho矩阵的设置方式:

GL.Ortho(-G_.MapSize * 1.5 ^ ZoomFactor, G_.MapSize * 1.5 ^ ZoomFactor, G_.MapSize * 1.5 ^ ZoomFactor, -G_.MapSize * 1.5 ^ ZoomFactor, -1, 1)

2 个答案:

答案 0 :(得分:1)

GL具有清晰的物体空间锥形,夹子空间,标准化设备坐标和窗口空间。您对glOrtho()glTranslate()的使用意味着您使用旧的固定功能,其中眼睛空间也是明确定义的。

如果要将窗口sapce点(如鼠标坐标)映射回对象空间,则需要反转gl执行的计算。顶点的转换管道如下:

  1. 通过对象空间顶点位置乘以模型视图矩阵MV以获得眼睛空间坐标(仅在固定功能GL中,在可编程管道中,此步骤完全由用户定义)
  2. 通过眼睛空间位置乘以投影矩阵P以获得剪辑空间位置(仅在固定功能GL中,在可编程管道中,此步骤完全由用户定义)
  3. 除以剪辑空间w分量以获得笛卡尔标准化设备坐标。在这个空间中,观察体积是沿每个轴在[-1,1]范围内的轴 - 铝合金立方体。 whit z = -1表示近平面,z = 1表示远平面
  4. 将视口转换为accout,将NDC转换为窗口空间。点(-1,1)将映射到视口的左下角像素(左下角),(1,1)映射到右上角像素的(右上角)的视口。 Z从[-1,1]转换为[0,1],可能会被指定的glDepthRange进一步转换,之后可能转换为某种整数表示。
  5. 如果您有一个给定的2D鼠标位置,您可以简单地反转该方案:

    1. 找到视口坐标(如果你使用完整的窗口,这是微不足道的,只要知道GL使用左下角的原点,而大多数窗口系统将原点放在左上角)。
    2. 撤消视口转换,将x和y置于[-1,-1]范围内。
    3. 现在你可以通过assuimg w = 1直接将它们用作剪辑空间坐标。在一般情况下,每个2d鼠标位置代表一条光线,因此您可以使用两个点来投射光线,例如z = -1和z = 1。但是,在正交投影的情况下,一点就足够了。因此,将逆投影P ^ -1乘以您的点的剪辑空间坐标。
    4. 你现在有了眼睛空间位置。通过眼睛空间坐标将逆模型视图矩阵MV ^ -1相乘以返回到对象空间。(在一般情况下,您应该知道必须将最终结果除以w分量,因为您在投影中使用正交投影,在ModelView中只进行仿射变换,w将为1,因此您可以忽略它。)
    5. 修改

      由于该操作很常见,因此还有一些实用程序功能可以实现此功能。当您使用GL的矩阵堆栈时,最简单的解决方案就是使用GLu库中的gluUnproject()。您所需要的只是点的3D窗口坐标,以及在绘制对象时使用的矩阵和视口设置,可以使用各种glGetDoublev()函数使用glGet查询。有full example at the old NeHe site

      使用现代GL,您必须自己完成所有这些。但是,流行的GLM库还有一个类似于GLU的glm::unProject方法。

答案 1 :(得分:0)

这只是我评论的扩展,这是unProjecting鼠标坐标到世界坐标的工作代码。它几乎是derhass所说的一个实际例子。 调用函数:

    Dim modelViewMatrix As Matrix4
    Dim projectionMatrix As Matrix4
    Dim viewport(4) As Integer
    GL.GetFloat(GetPName.ModelviewMatrix, modelViewMatrix)
    GL.GetFloat(GetPName.ProjectionMatrix, projectionMatrix)
    GL.GetInteger(GetPName.Viewport, viewport)
    Dim cords As Vector4 = GF.UnProject(projectionMatrix, modelViewMatrix, New Size(viewport(2), viewport(3)), New Vector2(e.Position.X, e.Position.Y))

功能:

    Public Function UnProject(ByRef projection As Matrix4, ByVal view As Matrix4, ByVal viewport As Size, ByVal mouse As Vector2) As Vector4
        Dim vec As Vector4

        vec.X = 2.0F * mouse.X / CSng(viewport.Width) - 1
        vec.Y = -(2.0F * mouse.Y / CSng(viewport.Height) - 1)
        vec.Z = 0
        vec.W = 1.0F

        Dim viewInv As Matrix4 = Matrix4.Invert(view)
        Dim projInv As Matrix4 = Matrix4.Invert(projection)

        Vector4.Transform(vec, projInv, vec)
        Vector4.Transform(vec, viewInv, vec)

        If vec.W > Single.Epsilon OrElse vec.W < Single.Epsilon Then
            vec.X /= vec.W
            vec.Y /= vec.W
            vec.Z /= vec.W
        End If

        Return vec
    End Function