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:
If I have a different point on my view window such as (1,3) for example:
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
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.