tcsavage's picture

VBOs won't render

Having tried to implement VBO in my application (where I was just using immediate mode before) for a while, I am getting increasingly frustrated by my situation.

Places I've looked for help include this thread on a VBO example http://www.opentk.com/node/425 and the Static VBO example.

This situation is as follows, there are no compile errors or warnings or even any runtime errors I can detect. It looks like the VBOs are populated correctly but when it comes to render time, I see nothing. There are some extra debug graphics (rendered in immediate mode) which do display but nothing I can do will make my VBOs draw.

I know my graphics card can support them (I've looked at various examples and my driver utility agrees) but I cannot get them to render in my application.

Here's the VBO class I'm using in it's entirety (mainly copied from the aforementioned thread):

using System;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
namespace Angelfall.Framework
{
 
	sealed class VertexBuffer
	{
		public int id;
 
		int Id {
			get {
				// Create an id on first use.
				if (id == 0) {
					GraphicsContext.Assert ();
 
					GL.GenBuffers (1, out id);
					if (id == 0)
						throw new Exception ("Could not create VBO.");
				}
 
				return id;
			}
		}
 
		int length;
 
		public VertexBuffer ()
		{
		}
 
		public void SetData (Vertex[] data)
		{
			if (data == null)
				throw new ArgumentNullException ("data");
 
			this.length = data.Length;
 
			int size = 0;
 
			GL.BindBuffer (BufferTarget.ArrayBuffer, Id);
			GL.BufferData (BufferTarget.ArrayBuffer, new IntPtr (data.Length * BlittableValueType.StrideOf(data)), data, BufferUsageHint.StaticDraw);
			GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size);
			if (data.Length * BlittableValueType.StrideOf(data) != size)
				throw new ApplicationException("Vertex data not uploaded correctly");
		}
 
		public void Render ()
		{
			GL.EnableClientState (ArrayCap.VertexArray);
			GL.EnableClientState (ArrayCap.NormalArray);
			GL.EnableClientState (ArrayCap.TextureCoordArray);
 
			GL.BindBuffer (BufferTarget.ArrayBuffer, Id);
			GL.VertexPointer (3, VertexPointerType.Float, Vertex.Stride, new IntPtr (0));
			GL.NormalPointer (NormalPointerType.Float, Vertex.Stride, new IntPtr (Vector3.SizeInBytes));
			GL.TexCoordPointer (2, TexCoordPointerType.Float, Vertex.Stride, new IntPtr (2 * Vector3.SizeInBytes));
			GL.DrawArrays (BeginMode.Triangles, 0, this.length);
		}
	}
}

and this is my vertex struct in its entirety (not originally copied but modified to fit with the example):

using System;
using System.Runtime.Serialization;
using System.Xml;
using System.Runtime.InteropServices;
 
using OpenTK;
 
namespace Angelfall.Framework
{
	/// <summary>
	/// Defines spatial position, normal and UV coordinates for a vertex.
	/// </summary>
	[Serializable()]
	public struct Vertex
	{
		/// <summary>
		/// Position of vertex relative to mesh origin.
		/// </summary>
		public Vector3 position;
 
		/// <summary>
		/// Vertex normal.
		/// </summary>
		public Vector3 normal;
 
		/// <summary>
		/// UV texture coordinates.
		/// </summary>
		public Vector2 texCoord;
 
		public static readonly int Stride = Marshal.SizeOf(default(Vertex));
 
		/// <summary>
		/// Construct from position.
		/// Normal and UV set to 0.
		/// </summary>
		/// <param name="Position">
		/// Position vector. <see cref="Vector3"/>
		/// </param>
		public Vertex(Vector3 Position)
		{
			// Set position to something fun.
			this.position = Position;
			this.normal = Vector3.Zero;
			this.texCoord = Vector2.Zero;
		}
 
		/// <summary>
		/// Constuct vertex from position, normal and UV.
		/// </summary>
		/// <param name="Position">
		/// <see cref="Vector3"/> position
		/// </param>
		/// <param name="Normal">
		/// <see cref="Vector3"/> normal
		/// </param>
		/// <param name="TexCoord">
		/// <see cref="Vector2"/> UV texture coordinates.
		/// </param>
		public Vertex(Vector3 Position, Vector3 Normal, Vector2 TexCoord)
		{
			// Set vectors.
			this.position = Position;
			this.normal = Normal;
			this.texCoord = TexCoord;
		}
 
		public override string ToString ()
		{
			return string.Format("[Vertex] {0}, {1}, {2}", position.ToString(), normal.ToString(), texCoord.ToString());
		}
 
	}
}

I know it's a bit of a long shot but if any mistakes jump out at anyone or if there are any suggestions, please let me know.

If anyone wants to see more code, I can provide it but I would think this would be enough.

This one's been annoying me for a long time. Any ideas?