dwmkerr / sharpgl

Use OpenGL in .NET applications. SharpGL wraps all modern OpenGL features and offers a powerful scene graph to aid development.
MIT License
755 stars 299 forks source link

VBO not working. #115

Closed dragon42 closed 9 years ago

dragon42 commented 9 years ago

I'm working on a WindowsForms application using .NET 4.0. I'm trying to draw an object using a VBO with an index buffer.

I initialize the VBO like this.

m_vertexVBOID = new uint[1];
gl.GenBuffers(1, m_vertexVBOID);
gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);
gl.BufferData(OpenGL.GL_ARRAY_BUFFER, m_vertices, OpenGL.GL_STATIC_DRAW);

m_indexVBOID = new uint[1];
gl.GenBuffers(1, m_indexVBOID);
gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indexVBOID[0]);
gl.BufferData(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indices, OpenGL.GL_STATIC_DRAW);

I then render the data like this.

gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);
gl.EnableVertexAttribArray(0);
gl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, new IntPtr(0));

gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);
gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);
gl.VertexPointer(3, sizeof(float)*3, m_vertices);

gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indexVBOID[0]);
gl.DrawElements(OpenGL.GL_TRIANGLES, m_numIndices, m_indices);

Unfortunately all I get is a blank screen. I am able to render this data using glBegin/glEnd, which works fine, if slowly. gl.GetError() always returns 'no error' after each of these calls. The frame rate counter does drop significantly when I try to render, so it seems to be doing something. Does anyone see anything obviously wrong with this code? I'm grateful for the help!

I'm running on Windows 7-64 bit, GeForce GT 650M, driver 347.52. My SharpGL control is set to OpenGL2_1. If I set it higher the built in frame rate counter disappears.

bitzhuwei commented 9 years ago

initialize the VBO like this:

m_vertexVBOID = new uint[1];
gl.GenBuffers(1, m_vertexVBOID);
gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);
gl.BufferData(OpenGL.GL_ARRAY_BUFFER, m_vertices, OpenGL.GL_STATIC_DRAW);
gl.VertexPointer(3, OpenGL.GL_FLOAT, 0, IntPtr.Zero);
gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);

m_indexVBOID = new uint[1];
gl.GenBuffers(1, m_indexVBOID);
gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indexVBOID[0]);
gl.BufferData(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indices, OpenGL.GL_STATIC_DRAW);

render the data like this:

gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);
gl.VertexPointer(3, OpenGL.GL_FLOAT, 0, IntPtr.Zero);
gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);
gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indexVBOID[0]);
gl.DrawElements(OpenGL.GL_TRIANGLES, m_numIndices, OpenGL.GL_UNSIGNED_SHORT, IntPtr.Zero);

Hope this helps. the best way to use VBO is using VAO+shader. I think it will help if you check out the 'ModernOpenGLSample' sample project which shows how it works.

dragon42 commented 9 years ago

Thank you, that did the trick!

Now a new question. I tried to add support for my array of vertex normals but the mesh renders as if there is no normal data.

My setup code looks like this. Any obvious problems?

// Get id for VBO vertex array
m_vertexVBOID = new uint[1];
gl.GenBuffers(1, m_vertexVBOID);
gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, m_vertexVBOID[0]);

// Allocate vertex/normal buffer
 int vboSize = (m_vertices.Length * sizeof(float)) + (m_normals.Length * sizeof(float));
gl.BufferData(OpenGL.GL_ARRAY_BUFFER, vboSize, IntPtr.Zero, OpenGL.GL_STATIC_DRAW);

// Copy vertex data to VBO.
IntPtr vertexArray = GCHandle.Alloc(m_vertices, GCHandleType.Pinned).AddrOfPinnedObject();
int vertexArraySize = m_vertices.Length * sizeof(float);
gl.BufferSubData(OpenGL.GL_ARRAY_BUFFER, 0, vertexArraySize, vertexArray);

// Copy normal data to VBO.
IntPtr normalArray = GCHandle.Alloc(m_normals, GCHandleType.Pinned).AddrOfPinnedObject();
int normalArraySize = m_normals.Length * sizeof(float);
gl.BufferSubData(OpenGL.GL_ARRAY_BUFFER, vertexArraySize, normalArraySize, normalArray);

// Enable vertex array
gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);
gl.VertexPointer(3, OpenGL.GL_FLOAT, 0, IntPtr.Zero);

// enable normal array
gl.EnableClientState(OpenGL.GL_NORMAL_ARRAY);
gl.NormalPointer(OpenGL.GL_FLOAT, 0, normalArray);

// Get id for VBO index array
m_indexVBOID = new uint[1];
gl.GenBuffers(1, m_indexVBOID);
gl.BindBuffer(OpenGL.GL_ELEMENT_ARRAY_BUFFER, m_indexVBOID[0]);

// VBO index size = size of vertex array + size of normal array
int indexSize = m_indices.Length * sizeof(int);
IntPtr indexArray = GCHandle.Alloc(m_indices, GCHandleType.Pinned).AddrOfPinnedObject();
gl.BufferData(OpenGL.GL_ELEMENT_ARRAY_BUFFER, indexSize, indexArray, OpenGL.GL_STATIC_DRAW);

I then just draw with DrawElements

gl.DrawElements(OpenGL.GL_TRIANGLES, GetNumIndices(), OpenGL.GL_UNSIGNED_INT, IntPtr.Zero);

All I can see the vertex data but it is all flat shaded with no lighting. I am able to get this to work with the glDrawArrays() approach and different initialization code that does not use an index buffer, but I'd rather use glDrawElements and an index buffer. Thanks again for the help!

bitzhuwei commented 9 years ago
gl.NormalPointer(OpenGL.GL_FLOAT, 0, normalArray);

I think the 'normalArray' should be IntPtr(vertexArraySize)

dragon42 commented 9 years ago

Thank you bitzhuwei. It all works now. You saved me much time and grief!