-you're recreating the VBO every render call. Not a big deal in this particular case, but you will want to fill it up once and then just render it each frame.
-you're not loading a model view matrix. I recommend just starting with an identity matrix.
-looks like you're drawing your triangles in clockwise order, but they should be counter clockwise, either swap the verts or the indices to make it draw in counter clockwise order
Here's my VBO class from a project that is similar to yours. Maybe you can use this to help troubleshoot, or just use however you want
using System;
using System.Runtime.InteropServices;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace SimEngine
{
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public Vector3 Position;
public Vector3 Normal;
public Vector2 TexCoord;
public static readonly int Stride = Marshal.SizeOf(default(Vertex));
}
public class VertexBuffer
{
public int myVertexId;
public int myIndexId;
public BeginMode myMode=BeginMode.Triangles;
public uint myVertexLength;
public uint myIndexLength;
int myDataOffset = 0;
int myByteOffset = 0;
public enum IndexType { USHORT, UINT};
IndexType myIndexType;
public VertexBuffer()
{
init();
}
public bool init()
{
GL.GenBuffers(1, out myVertexId);
GL.GenBuffers(1, out myIndexId);
return true;
}
public int vertexOffset
{
get { return myDataOffset; }
set { myDataOffset = value; myByteOffset = myDataOffset * Vertex.Stride; }
}
public void SetVertexData(Vertex[] data)
{
SetVertexData(data, (uint)data.Length);
}
public void SetVertexData(Vertex[] data, uint count)
{
if (data == null)
throw new ArgumentNullException("vertex data not found");
myVertexLength = count;
GL.BindBuffer(BufferTarget.ArrayBuffer, myVertexId);
GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(data.Length * Vertex.Stride), data, BufferUsageHint.StaticDraw);
}
public void SetIndexData(ushort[] data)
{
SetIndexData(data, (ushort)data.Length);
}
public void SetIndexData(ushort[] data, uint count)
{
if (data == null)
throw new ArgumentNullException("index data not found");
myIndexType = IndexType.USHORT;
myIndexLength = count;
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(data.Length * sizeof(ushort)), data, BufferUsageHint.DynamicDraw);
}
public void SetIndexData(uint[] data)
{
SetIndexData(data, (ushort)data.Length);
}
public void SetIndexData(uint[] data, uint count)
{
if (data == null)
throw new ArgumentNullException("index data not found");
myIndexType = IndexType.UINT;
myIndexLength = count;
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(data.Length * sizeof(uint)), data, BufferUsageHint.DynamicDraw);
}
public void renderRange(int offset, int count)
{
//we're binding the normals as colors here for visualizing the triangles
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, myVertexId);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
GL.VertexPointer(3, VertexPointerType.Float, Vertex.Stride, new IntPtr(0 + myByteOffset));
GL.NormalPointer(NormalPointerType.Float, Vertex.Stride, new IntPtr(Vector3.SizeInBytes + myByteOffset));
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vertex.Stride, new IntPtr(2 * Vector3.SizeInBytes + myByteOffset));
if (myIndexType == IndexType.USHORT)
GL.DrawRangeElements(myMode, 0, myIndexLength, count, DrawElementsType.UnsignedShort, new IntPtr(offset * 2));
else
GL.DrawRangeElements(myMode, 0, myIndexLength, count, DrawElementsType.UnsignedInt, new IntPtr(offset * 4));
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
Draw.checkError("VBO::renderRange");
}
public void render()
{
//we're binding the normals as colors here for visualizing the triangles
GL.EnableClientState(ArrayCap.VertexArray);
GL.EnableClientState(ArrayCap.NormalArray);
GL.EnableClientState(ArrayCap.TextureCoordArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, myVertexId);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, myIndexId);
GL.VertexPointer(3, VertexPointerType.Float, Vertex.Stride, new IntPtr(0 + myByteOffset));
GL.NormalPointer(NormalPointerType.Float, Vertex.Stride, new IntPtr(Vector3.SizeInBytes + myByteOffset));
GL.TexCoordPointer(2, TexCoordPointerType.Float, Vertex.Stride, new IntPtr(2 * Vector3.SizeInBytes + myByteOffset));
int batchSize = 63000; //multiple of 4 and 3
int count, rendered;
rendered = 0;
if (myIndexLength <= batchSize)
{
count = (int)myIndexLength;
}
else
{
count = batchSize;
}
while (rendered < myIndexLength)
{
if(myIndexType==IndexType.USHORT)
GL.DrawRangeElements(myMode, 0, myIndexLength, count, DrawElementsType.UnsignedShort, new IntPtr(rendered * 4));
else
GL.DrawRangeElements(myMode, 0, myIndexLength, count, DrawElementsType.UnsignedInt, new IntPtr(rendered * 4));
rendered += count;
if (myIndexLength - rendered < batchSize)
{
count = (int)myIndexLength - rendered;
}
}
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
GL.DisableClientState(ArrayCap.NormalArray);
GL.DisableClientState(ArrayCap.TextureCoordArray);
Draw.checkError("VBO::render");
}
}
}
*edited for formating and took my copyright notice off, this code is free!