Glasswalker's picture

Help for absolute beginner (rendering cube)

Hey, so I'm an absolute beginner at this, done no real OpenGL code before (walked through a few nehe tutorials, but haven't fully grasped it yet).

Trying to just build a basic level abstraction library to get the lowlevel stuff out of the way initially so I can just call higher level primitives (cubes initially).

I've bounced around some of the documentation, and some references and tutorials on here. and came up with the following classes, I'm trying to render a basic cube. But it's not rendering anything at all... It runs without error, but doesn't render anything but the clear color...

Can anyone either point me in the right direction? or give me some code examples that will achieve what I'm shooting for below?

Any help would be much appreciated!

Here's my code:

Mesh.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
namespace DCSGame
{
    class Mesh
    {
        private int VBO;
        public Vector3d[] vertices;
 
        public void Render()
        {
            GL.EnableVertexAttribArray(0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.VBO);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
            GL.DrawArrays(BeginMode.Triangles, 0, this.vertices.Count());
            GL.DisableVertexAttribArray(0);
        }
 
        public void CreateVBO()
        {           
            GL.GenBuffers(1, out this.VBO);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.VBO);
            GL.BufferData<Vector3d>(BufferTarget.ArrayBuffer, new IntPtr(this.vertices.Length * Vector3d.SizeInBytes), this.vertices, BufferUsageHint.StaticDraw);
        }
 
    }
}

Cube.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
namespace DCSGame
{
    class Cube : Mesh
    {
        private int VBO;
 
        public double Size;
        public Vector3d Position;
        public Vector3d Rotation;
 
        public Cube(double Size, Vector3d Pos, Vector3d Rot)
        {
            this.Size = Size;
            this.Position = Pos;
            this.Rotation = Rot;
            this.GenerateVertices();
            this.CreateVBO();
        }
 
        private void GenerateVertices()
        {
            double offset = this.Size/2;
            this.vertices = new Vector3d[13];
 
            //Face 1
            this.vertices[00] = new Vector3d(100, 100, -100);
            this.vertices[01] = new Vector3d(100, 300, -100);
            this.vertices[02] = new Vector3d(300, 300, -100);
 
            //Face 2
            this.vertices[03] = new Vector3d(300, 300, -300);
            this.vertices[04] = new Vector3d(300, 100, -300);
 
            //Face 3
            this.vertices[05] = new Vector3d(100, 100, -100);
            this.vertices[06] = new Vector3d(100, 100, -300);
 
            //Face 4
            this.vertices[07] = new Vector3d(100, 300, -300);
            this.vertices[08] = new Vector3d(100, 300, -100);
 
            //Face 5
            this.vertices[09] = new Vector3d(100, 300, -100);
            this.vertices[10] = new Vector3d(100, 300, -300);
 
            //Face 6
            this.vertices[11] = new Vector3d(100, 100, -300);
            this.vertices[12] = new Vector3d(300, 100, -300);         
        }
    }
}

Program.cs:

// Released to the public domain. Use, modify and relicense at will.
 
using System;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
using DCSSim;
 
namespace DCSGame
{
    class Game : GameWindow
    {
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game()
            : base(1024, 768, GraphicsMode.Default, "Game")
        {
            VSync = VSyncMode.On;
        }
 
        /// <summary>Load resources here.</summary>
        /// <param name="e">Not used.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
            GL.ClearColor(0.1f, 0.2f, 0.4f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
        }
 
        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
 
            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
 
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }
 
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
 
            if (Keyboard[Key.Escape])
                Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            Cube TestCube = new Cube(10, new Vector3d(0, 0, 0), new Vector3d(0, 0, 0));
            TestCube.Render();
 
            SwapBuffers();
        }
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(60.0);
            }
        }
    }
}

Comments

Comment viewing options

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

Some recommendations:

/ / First: Create TestCube in OnLoad () and not in OnRenderFrame ()
/ / Second: Delete VBO private int; in class Cube.
/ / Third: Right GL.Vertex3 (-1f, 1f,-1f); Wrong: GL.Vertex3 (-1.1, -1); Add 'f' to the number.
/ / Fourth: If you draw a cube as triangles, need 36 vertices positions and now only have 13 in Cube.vertices []

Next, the code of the modified files:

Program.cs

// Released to the public domain. Use, modify and relicense at will.
 
using System;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
//using DCSSim;
 
namespace DCSGame
{
	// Primero: Crear TestCube en OnLoad() y no en OnRenderFrame()
	// Segundo: Eliminar private int VBO; en la clase Cube.
	// tercero: Correcto GL.Vertex3(-1f,1f,-1f); Incorrecto: GL.Vertex3(-1,1,-1);
	// cuarto: Si dibujas un cubo como triángulos, necesitas 36 posiciones de vertice y ahora solo tienes 13 en Cube.vertices[]
 
    class Game : GameWindow
    {
    	Cube TestCube;
 
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game()
            : base(1024, 768, GraphicsMode.Default, "Game")
        {
            VSync = VSyncMode.On;
        }
 
        /// <summary>Load resources here.</summary>
        /// <param name="e">Not used.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
            GL.ClearColor(0.1f, 0.2f, 0.4f, 0.0f);
            GL.Enable(EnableCap.DepthTest);
            GL.Enable(EnableCap.ColorMaterial);
 
            TestCube = new Cube(10, new Vector3d(0, 0, 0), new Vector3d(0, 0, 0));
        }
 
        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
 
            GL.Viewport(0, 0, Width, Height);
 
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 1000.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }
 
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            base.OnUpdateFrame(e);
 
            if (Keyboard[Key.Escape])
                Exit();
        }
 
        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.PushMatrix();
    		GL.Translate(-1, -2, -10); // cube position
 
    		TestCube.Render();
 
    		GL.PopMatrix();
 
            draw1();
 
            SwapBuffers();
        }
 		void draw1()
		{
    		GL.PushMatrix();
    		GL.Translate(-2f, 0, -10f); // move to upper left corner
    		GL.Begin(BeginMode.Quads);
        	// face v0-v1-v2-v3
        	GL.Normal3(0,0,1f);
        	GL.Color3(1f,1f,1f);
        	GL.Vertex3(1f,1f,1f);
        	GL.Color3(1f,1f,0);
        	GL.Vertex3(-1f,1f,1f);
        	GL.Color3(1f,0,0);
        	GL.Vertex3(-1f,-1f,1f);
        	GL.Color3(1f,0,1f);
        	GL.Vertex3(1f,-1f,1f);
 
        	// face v0-v3-v4-v6
        	GL.Normal3(1f,0,0);
        	GL.Color3(1f,1f,1f);
        	GL.Vertex3(1f,1f,1f);
        	GL.Color3(1f,0,1f);
        	GL.Vertex3(1f,-1f,1f);
        	GL.Color3(0,0,1f);
        	GL.Vertex3(1f,-1f,-1f);
        	GL.Color3(0,1f,1f);
        	GL.Vertex3(1f,1f,-1f);
 
        	// face v0-v5-v6-v1
        	GL.Normal3(0,1f,0);
        	GL.Color3(1f,1f,1f);
        	GL.Vertex3(1f,1f,1f);
        	GL.Color3(0,1f,1f);
        	GL.Vertex3(1f,1f,-1f);
        	GL.Color3(0,1f,0);
        	GL.Vertex3(-1f,1f,-1f);
        	GL.Color3(1f,1f,0);
        	GL.Vertex3(-1f,1f,1f);
 
        	// face  v1-v6-v7-v2
        	GL.Normal3(-1f,0,0);
        	GL.Color3(1f,1f,0);
        	GL.Vertex3(-1f,1f,1f);
        	GL.Color3(0,1f,0);
        	GL.Vertex3(-1f,1f,-1f);
        	GL.Color3(0,0,0);
        	GL.Vertex3(-1f,-1f,-1f);
        	GL.Color3(1,0,0);
        	GL.Vertex3(-1f,-1f,1f);
 
        	// face v7-v4-v3-v2
        	GL.Normal3(0,-1f,0);
        	GL.Color3(0,0,0);
        	GL.Vertex3(-1f,-1f,-1f);
        	GL.Color3(0,0,1);
        	GL.Vertex3(1f,-1f,-1f);
        	GL.Color3(1f,0,1f);
        	GL.Vertex3(1f,-1f,1f);
        	GL.Color3(1f,0,0);
        	GL.Vertex3(-1f,-1f,1f);
 
        	// face v4-v7-v6-v5
        	GL.Normal3(0,0,-1f);
        	GL.Color3(0,0,1f);
        	GL.Vertex3(1f,-1f,-1f);
        	GL.Color3(0,0,0);
        	GL.Vertex3(-1f,-1f,-1f);
        	GL.Color3(0,1f,0);
        	GL.Vertex3(-1f,1f,-1f);
        	GL.Color3(0,1f,1f);
        	GL.Vertex3(1f,1f,-1f);
    		GL.End();
 
    		GL.PopMatrix();
		}
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(60.0);
            }
        }
    }
}

Mesh.cs

using System;
using System.Collections.Generic;
using System.Text;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
namespace DCSGame
{
    class Mesh
    {
        private int VBO;
        public Vector3d[] vertices;
 
        public void Render()
        {
            //GL.EnableVertexAttribArray(0);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.VBO);
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.VertexPointer(3, VertexPointerType.Double, 0, 0);
            //GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 0, 0);
            GL.DrawArrays(BeginMode.Triangles, 0, this.vertices.Length);
            //GL.DisableVertexAttribArray(0);
            GL.DisableClientState(ArrayCap.VertexArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
 
        public void CreateVBO()
        {           
            GL.GenBuffers(1, out this.VBO);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.VBO);
            GL.BufferData<Vector3d>(BufferTarget.ArrayBuffer, new IntPtr(this.vertices.Length * Vector3d.SizeInBytes), this.vertices, BufferUsageHint.StaticDraw);
        }
 
    }
}

Cube.cs

using System;
using System.Collections.Generic;
using System.Text;
 
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
 
namespace DCSGame
{
    class Cube : Mesh
    {
        //private int VBO;
 
        public double Size;
        public Vector3d Position;
        public Vector3d Rotation;
 
        public Cube(double Size, Vector3d Pos, Vector3d Rot)
        {
            this.Size = Size;
            this.Position = Pos;
            this.Rotation = Rot;
            this.GenerateVertices();
            this.CreateVBO();
        }
 
        private void GenerateVertices()
        {
            double offset = this.Size/2;
            this.vertices = new Vector3d[13];
 
            //Face 1
            this.vertices[00] = new Vector3d(1f, 1f, -1f);
            this.vertices[01] = new Vector3d(1f, 3f, -1f);
            this.vertices[02] = new Vector3d(3f, 3f, -1f);
 
            //Face 2
            this.vertices[03] = new Vector3d(3f, 3f, -3f);
            this.vertices[04] = new Vector3d(3f, 1f, -3f);
 
            //Face 3
            this.vertices[05] = new Vector3d(1f, 1f, -1f);
            this.vertices[06] = new Vector3d(1f, 1f, -3f);
 
            //Face 4
            this.vertices[07] = new Vector3d(1f, 3f, -3f);
            this.vertices[08] = new Vector3d(1f, 3f, -1f);
 
            //Face 5
            this.vertices[09] = new Vector3d(1f, 3f, -1f);
            this.vertices[10] = new Vector3d(1f, 3f, -3f);
 
            //Face 6
            this.vertices[11] = new Vector3d(1f, 1f, -3f);
            this.vertices[12] = new Vector3d(3f, 1f, -3f);         
        }
    }
}

Visit these links:

Nate Robins - OpenGL Tutorials

OpenGL Vertex Buffer Object (VBO)

Mind, we've all gone through these problems in the beginning!

Miguel

Norris's picture

Hi Glasswalker
I agree with Migueltk. You have a bad "thinking" for creating your vertices. Depending on the Mesh you want to render, you have more than one option. For some one, you can "reuse"/share the same vertex for some triangles, but for a cube it is much simple to only use one vertex one time.
So you have 3 vertices per triangle, 6 for one face (2 triangles), so 6vertices x 6faces = 36 vertices.
All this is due to the normals for your faces.
Also, maybe working with vbos when you are new to OpenGL is not good. I had very hard time to translate a simple code to vbos.
You really need to understand why you had shared(or not) vertices and how your normals work with them before jumping to vbos.

heeeuuuu ... sorry for my bad english !