Dan's picture

3D Woes.

I am an entirely self-taught programmer.

Everything I've ever learned I have taught myself, and I don't really like asking for help at the best of times, because part of the appeal for me is figuring things out on my own.

In the past I have taught myself, VB6, VB.Net, ASP, Html, MySQL and have used, DirectX7, DirectX9, and now OpenTK.
I understand sockets, multi threading, encryption, and I can make 2D games using OpenTK or Dx9 without any problem at all.

I give that as an introduction so that you can understand a few things about me, firstly I am determined, secondly because I am self taught, I've missed out on much lingo that I would have otherwise learned.

When answering any of my questions, feel free to post any of the code in c# as while I cannot write it, I can read it and convert it with ease.

Now for my question.

As I said I've used Dx7 -> OpenTK in the last few years to create 2D games, but every time I attempt to do anything in 3D I get stuck, I've tried countless tutorials, and even tried copy/pasting examples, and I can never ever seem to get any to work for me, much to my frustration, as a result each time I sadly end up getting annoyed and resorting to making something in 2D, which is within my ability.

So now I'm going to post some code, any pointers are much appreciated.

Start.vb

Imports System.IO
 
 
Public Class Start
 
    Shared Sub Main(ByVal args As String())
 
        Dim Eng As New Engine 'Start up a new engine object
        Dim gThread As New System.Threading.Thread(AddressOf Eng.EngLoad)
        gThread.Start()
 
        Do Until Eng.Running = False
            System.Threading.Thread.Sleep(1)
            Application.DoEvents()
        Loop
 
    End Sub

Engine.vb

Imports OpenTK.Graphics.OpenGL
Imports OpenTK
 
Imports System.Drawing.Text
 
Public Class Engine
 
 
    Private Context As New OpenTK.Audio.AudioContext 'This is required for any sound to work
    Public Running As Boolean = True
    Public ScrWidth As Integer = 800
    Public ScrHeight As Integer = 600
    Public Debug As Boolean = True
    Public Game As Frm
 
    Public Sub EngLoad()
 
        Game = New Frm 'create a new instance of the game form
        Game.ClientSize = New System.Drawing.Size(ScrWidth, ScrHeight) 'change the form resultion to match the game resolution
        Game.MaximizeBox = False 'don't want people resizing the game
        Game.MinimizeBox = False
        Game.Text = "Project Rebirth (Enigma)" 'set the game text
 
        Game.GlControl1.Left = 0 'Set the OpenGL control to be in the top left
        Game.GlControl1.Top = 0
        Game.GlControl1.Size = New System.Drawing.Size(ScrWidth, ScrHeight) 'resize the openGL control to use all the avalible space.
 
        Game.Show()
 
        Do Until Game.Loaded = True
            System.Threading.Thread.Sleep(1)
            Application.DoEvents()
        Loop
 
        Call Game.SetupViewpoint() 'setup the viewpoint so OpenGL knows to use all of the space
        GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit) 'clear the backbuffer
        Game.GlControl1.SwapBuffers()
        GL.Enable(EnableCap.DepthTest)
 
        Call Me.Run()
 
    End Sub
 
    Private Sub Run()
 
 
        Do Until Game.Running = False
            Application.DoEvents() 'accept input from the ui
            System.Threading.Thread.Sleep(0) 'allow the cpu to be used by other processes.
            GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit) 'clear the backbuffer
 
            Try
                'rendering happens here
                        'GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line)
 
                        GL.Begin(BeginMode.Quads)
 
                        GL.Color4(Color.LimeGreen)
 
                        'Front face?
                        GL.Vertex3(100, 100, 0.5)
                        GL.Vertex3(200, 100, 0.5)
                        GL.Vertex3(200, 200, 0.5)
                        GL.Vertex3(100, 200, 0.5)
 
                        'back face
                        GL.Color4(Color.Red)
                        GL.Vertex3(100, 100, -0.5)
                        GL.Vertex3(100, 200, -0.5)
                        GL.Vertex3(200, 200, -0.5)
                        GL.Vertex3(200, 100, -0.5)
 
                        'right face?
                        GL.Color4(Color.Blue)
                        GL.Vertex3(200, 100, -0.5)
                        GL.Vertex3(200, 200, -0.5)
                        GL.Vertex3(200, 200, 0.5)
                        GL.Vertex3(200, 100, 0.5)
 
                        GL.End()
 
            Try
                Game.GlControl1.SwapBuffers() 'Flip the backbuffer to the screen
            Catch ex As Exception
 
            End Try
 
        Loop
 
        Me.Running = False
 
    End Sub
 
End Class

Frm.vb

Imports OpenTK.Graphics.OpenGL
Imports OpenTK
 
Public Class Frm
 
    Public Loaded As Boolean = False
    Public Running As Boolean = False
    Public MouseX As Integer = 0
    Public MouseY As Integer = 0
    Public MouseUpdate As Boolean
    Public MouseButton(0 To 2) As String
    Public CollectKeys As Boolean = False
    Public KeyCollection As String
    Dim curs As Cursor
 
    Private Sub GlControl1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GlControl1.Load
        Loaded = True
        Running = True
        GL.ClearColor(Color.White)
    End Sub
 
    Public Sub SetupViewpoint()
        Dim w As Integer = GlControl1.Width
        Dim h As Integer = GlControl1.Height
 
        GL.MatrixMode(MatrixMode.Projection)
        GL.LoadIdentity()
        GL.Ortho(0, w, h, 0, -1, 1) 'bottom left has cordinate 0,0
        GL.Viewport(0, 0, w, h) 'use all of the glcontrol paining area
        GL.MatrixMode(MatrixMode.Modelview)
        GL.LoadIdentity()
 
    End Sub
 
    Private Sub GlControl1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles GlControl1.MouseDown
        MouseUpdate = True
 
 
        Dim state As String
        state = Control.MouseButtons.ToString()
 
        If InStr(state, "Left") Then
            If MouseButton(0) <> "hold" Then
                MouseButton(0) = "true"
            End If
        Else
            MouseButton(0) = "false"
        End If
 
        If InStr(state, "Middle") Then
            If MouseButton(1) <> "hold" Then
                MouseButton(1) = "true"
            End If
        Else
            MouseButton(1) = "false"
        End If
 
        If InStr(state, "Right") Then
            If MouseButton(2) <> "hold" Then
                MouseButton(2) = "true"
            End If
        Else
            MouseButton(2) = "false"
        End If
 
    End Sub
 
 
    Private Sub GlControl1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles GlControl1.MouseMove
 
 
 
        MouseX = e.X
        MouseY = e.Y
 
        MouseUpdate = True
 
    End Sub
 
 
    Private Sub GlControl1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles GlControl1.MouseUp
        Call GlControl1_MouseDown(sender, e)
    End Sub
 
    Private Sub Frm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
 
        Running = False
 
    End Sub
 
    Private Sub Frm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
 
        MouseButton(0) = "false"
        MouseButton(1) = "false"
        MouseButton(2) = "false"
 
        Dim path As String = System.IO.Path.GetTempPath & "Enigma\"
 
        Dim zp As New ArchiveAccesss
        zp.Extract(Application.StartupPath & "/Content/Console.dat", "trans.cur", path)
        curs = New Cursor(path & "trans.cur")
 
        System.Windows.Forms.Cursor.Current = curs
        GlControl1.Cursor = curs
    End Sub
 
    Private Sub GlControl1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles GlControl1.KeyPress
 
        If CollectKeys = True Then
 
            KeyCollection += e.KeyChar
 
        End If
 
    End Sub
 
    Private Sub GlControl1_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles GlControl1.MouseEnter
 
    End Sub
 
    Private Sub GlControl1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles GlControl1.MouseLeave
 
    End Sub
End Class

It doesn't seem to matter what value I put for the z axis, I never seem to be changing the "depth" of the square.
I have a 2D engine written in OpenTK, and DirectX, but I think there is something I'm just *not getting* when it comes to 3D..

any pointers are really appreciated at this point, because I am 100% frustrated.

What I really would like to be able to do is to get just a 3D cube that I can rotate with a button press so that I can see exactly what is going on at each step.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture
Quote:

It doesn't seem to matter what value I put for the z axis, I never seem to be changing the "depth" of the square.

This is because you are using an orthographic projection matrix (GL.Ortho). If you wish to make objects appear smaller than they are, you need to use a perspective projection:

Dim proj As Matrix4 = Matrix4.CreatePerspectiveFieldOfView(60, Width / CType(Height, Single), 1, 100)
GL.MatrixMode(MatrixMode.Projection)
GL.LoadMatrix(proj)
Dan's picture
the Fiddler wrote:
Quote:

It doesn't seem to matter what value I put for the z axis, I never seem to be changing the "depth" of the square.

This is because you are using an orthographic projection matrix (GL.Ortho). If you wish to make objects appear smaller than they are, you need to use a perspective projection:

Dim proj As Matrix4 = Matrix4.CreatePerspectiveFieldOfView(60, Width / CType(Height, Single), 1, 100)
GL.MatrixMode(MatrixMode.Projection)
GL.LoadMatrix(proj)

I found out by playing with it that Matrix4.Create perspective doesn't work because the first value is invalid, quick google tells me it has to be > 0 and < then Pi, because it works in radians.
But trying various values for it results in me getting nothing at all now, instead of it just rendering 2D squares.

Is there anything anywhere I could read that would give me a better understanding of 3D and how OpenGL works?
I'm no stranger to reading entire books.

I'm honestly at a loss, everything I try and do involving 3D just seems to fail miserably.

the Fiddler's picture

You are right, the first parameter must be in radians (try MathHelper.PiOverTwo or so).

If you see nothing on screen, chances are your camera is pointed the wrong way (the objects are rendered behind your viewpoint). Try running the OpenTK Example Browser and check the first few OpenGL examples. They are written in C#, but the OpenGL code is identical - these tutorials should provide a good starting point for 3d.

It might also be a good idea to read up on linear algebra (vector and matrix math). 3d is math-heavy and the more linear algebra you know, the simpler everything will appear.