1

I have been searching all over with Google and this site for an answer but I still get confused as to how one goes about converting the coordinates on the screen to the coordinate in model space. I do know the distance from the origin (0,0,0) to my camera, which is also the viewport's center:

enter image description here

If I have a different point on my view window such as (1,3) for example:

enter image description here

What is the best way to either mathematically calculate the new point in model view or to use matrix functions to determine it?

I apologize if this is considered "easy" for some people but I was hoping someone would post a good example using my sample coordinate since I am still rather confused.

Here is the matrix call that is done on every frame:

Public Sub SetupViewport()
    Dim w As Integer = GlControl1.Width
    Dim h As Integer = GlControl1.Height
    Dim perspective1 As Matrix4 = cam.GetViewMatrix() * Matrix4.CreatePerspectiveFieldOfView(1.3F, ClientSize.Width / CSng(ClientSize.Height), 0.1F, 200.0F)


    GL.MatrixMode(MatrixMode.Projection)
    GL.LoadIdentity()
    GL.LoadMatrix(perspective1)
    GL.Viewport(0, 0, w, h)

End Sub

This is done to allow me to rotate the camera using the cam matrix. I know generally in Open GL that you rotate the scene and not the camera but since I am using this as a CAD program, I am rotating my camera around the origin.

For testing purposes I have been constructing a line from what I calculate as the calculated start point, to the origin. As the title states, I do not wish to use gluunproject since I have read that this is based off of Tao framework so shouldn't be used.

My Draw Sub

Private Sub GlControl1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles GlControl1.Paint

    GL.Clear(ClearBufferMask.ColorBufferBit)
    GL.Clear(ClearBufferMask.DepthBufferBit)
    GL.DepthMask(True)
    GL.Enable(EnableCap.DepthTest)
    GL.ClearDepth(1.0F)



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


    Dim lightColor0 As Single() = {intensity, intensity, intensity, 1.0F}
    Dim lightPos0 As Single() = {camx, camy, camz, 1.0F}


    GL.Light(LightName.Light0, LightParameter.Diffuse, lightColor0)
    GL.Light(LightName.Light0, LightParameter.Position, lightPos0)
    GL.Enable(EnableCap.Light0)



    Dim mat_specular As Single() = {1.0F, 1.0F, 1.0F, 1.0F}
    Dim mat_shininess As Single() = {50.0F}


    GL.Material(MaterialFace.Front, MaterialParameter.Specular, mat_specular)
    GL.Material(MaterialFace.Front, MaterialParameter.Shininess, mat_shininess)


    GL.Disable(EnableCap.Lighting)

    GL.Begin(PrimitiveType.Lines)
    GL.Color3(Color.Red)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(100, 0, 0)

    GL.Color3(Color.Green)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(0, 100, 0)

    GL.Color3(Color.Blue)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(0, 0, 100)
    GL.End()


    GL.Begin(PrimitiveType.Lines)
    GL.Color3(Color.DarkRed)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(-100, 0, 0)

    GL.Color3(Color.DarkGreen)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(0, -100, 0)

    GL.Color3(Color.DarkBlue)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(0, 0, -100)
    GL.End()

    Dim projmatrix As Matrix4
    GL.GetFloat(GetPName.ProjectionMatrix, projmatrix)
    Dim mouse_ As New Vector2(_mouseStartX, _mouseStartY)
    Dim returnvec As Vector4

    returnvec = UnProject(projmatrix, cam.GetViewMatrix(), GlControl1.Size, mouse_)

    GL.Begin(PrimitiveType.Lines)
    GL.Color3(Color.Orange)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(returnvec.X, returnvec.Y, returnvec.Z)
    GL.End()


    GL.Enable(EnableCap.Lighting)

    draw_extras()


    GL.Flush()
    GlControl1.SwapBuffers()
End Sub
Eric F
  • 899
  • 2
  • 21
  • 45
  • 1
    There are several open source implementations of gluUnProject. Why don't you have a look at them and reimplement it in your program; then you're independent from any external implmentation. – datenwolf Sep 19 '15 at 09:59
  • I guess I didn't think of that.. so you can have gluUnProject without glu loaded? Basically writing your own function? Isn't glu basically outdated as far as what I read? – Eric F Sep 21 '15 at 16:43
  • Yes GLU is outdated. But that does not mean, that it's not fair game to be used as a cheat-sheet. gluUnProject is *so* simple, you can fit it in well under 20 lines of code. – datenwolf Sep 21 '15 at 16:53
  • Thank you datenwolf. With your help I have made it work. – Eric F Sep 21 '15 at 19:52
  • Actually... I take that back.. It mostly works. It works until I start to rotate the camera, thus changing the cam.getviewmatrix() portion. Any ideas? – Eric F Sep 21 '15 at 19:57
  • Rookie Mistake: **Never** (!!!) apply camera transformations to the projection matrix. It's the equivalent of yanking out the lens of the camera's body and walking with it through the room while keeping the camera settled on the tripod. Camera transformations **always** go into the modelview matrix. – datenwolf Sep 21 '15 at 20:17
  • I am sorry for the noob questions but where do you see me transforming it to the projection matrix and how do I go about fixing this? – Eric F Sep 21 '15 at 20:25
  • Well you're loading the matrix after `GL.MatrixMode(MatrixMode.Projection)`. The modelview matrix would be selected with MatrixMode.Modelview. gluUnProject takes two matrices (for a reason): The projection (which is kind of the objective lens) and the modelview (that does the view transformation). – datenwolf Sep 21 '15 at 21:15
  • If I change it to modelview then the rotation no longer works. How would I fix that then? I do call the modelview matrix in my draw event. I have posted my draw event in the question as well now. – Eric F Sep 22 '15 at 12:23
  • Nevermind I solved it again. Once again thank you for all of your help datenwolf – Eric F Sep 22 '15 at 12:53

1 Answers1

1

Thank you datenwolf for getting me down the right path. What I have done to solve my problem is I wrote an unproject function, with help of a few sites:

Public Shared Function UnProject(ByRef projection As Matrix4, view As Matrix4, viewport As Size, 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

I have a mouse move event handler that simply captures the mouse location on the screen and saves the coordinates to two global variables.. Within my draw function I then call my new function and draw a line that extends from the origin to my mouse position:

Dim projmatrix As Matrix4
    GL.GetFloat(GetPName.ProjectionMatrix, projmatrix)
    Dim modelmatrix As Matrix4
    GL.GetFloat(GetPName.ModelviewMatrix, modelmatrix)

    Dim mouse_ As New Vector2(_mouseStartX, _mouseStartY)
    Dim returnvec As Vector4

    returnvec = UnProject(projmatrix, modelmatrix, GlControl1.Size, mouse_)

    GL.Begin(PrimitiveType.Lines)
    GL.Color3(Color.Orange)
    GL.Vertex3(0, 0, 0)
    GL.Vertex3(returnvec.X, returnvec.Y, returnvec.Z)
    GL.End()

I also had to change my setupviewport function:

Public Sub SetupViewport()
    Dim w As Integer = GlControl1.Width
    Dim h As Integer = GlControl1.Height

    Dim perspective1 As Matrix4 = cam.GetViewMatrix() * Matrix4.CreatePerspectiveFieldOfView(1.3F, ClientSize.Width / CSng(ClientSize.Height), 0.1F, 200.0F)


    GL.MatrixMode(MatrixMode.Projection)
    GL.LoadIdentity()
    GL.LoadMatrix(perspective1)
    GL.MatrixMode(MatrixMode.Modelview)
    GL.LoadIdentity()
    GL.Viewport(0, 0, w, h)
    GL.Enable(EnableCap.DepthTest)
    GL.DepthFunc(DepthFunction.Less)

End Sub

The result is a line that has one side always on the origin and the other side always where the mouse is which is a fantastic example to show this working.

enter image description here

Eric F
  • 899
  • 2
  • 21
  • 45