Reputation: 185
I'm writing a simple scene graph, and I have a mesh class that keeps track of a vertex array object, vertex buffer object and an index buffer object.
When I initialize the mesh objects and populate them with data, it seems that the last created vertex buffer is the one being used when drawing, even when I bind a different vertex array object.
When rendering, if I only bind the vertex array, any meshes other than the last initialized one have the vertices of the last initialized mesh (but the correct indices, making them look wrong).
The only way I got it to work is to bind the vertex buffer object again right after I bind the vertex array object. This contradicts every documentation or comment I read anywhere.
// Geometry class
class Geometry
{
public override void Render()
{
this.Mesh.bind(); // bind mesh
this.Material.bind(); // bind shader. This also uses attribute locations stored in the shader object to enable vertex attributes
this.Data.Render();
this.Mesh.unbind(); // bind 0 to vertex array
this.Material.unbind(); // use program 0
}
}
// base mesh class
class Mesh
{
public override void init()
{
// ... truncated code for creating vertices ..
vertexArray = GL.GenVertexArray();
GL.BindVertexArray(vertexArray);
GL.GenBuffers(2, buffers);
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * Vertex.SizeInBytes), vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffers[1]);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Count * sizeof(uint)), indices.ToArray(), BufferUsageHint.StaticDraw);
numPoints = vertices.Length;
numIndices = indices.Count;
GL.BindVertexArray(0);
}
public void bind()
{
GL.BindVertexArray(vertexArray);
// I had to add this line to make meshes render correctly
GL.BindBuffer(BufferTarget.ArrayBuffer, buffers[0]);
}
public void unbind()
{
GL.BindVertexArray(0);
}
public override void Render()
{
GL.DrawElements(PrimitiveType.Triangles, numIndices, DrawElementsType.UnsignedInt, IntPtr.Zero);
}
public override void Update(float t, float deltaT, int xDelta, int yDelta, int zDelta, MouseState mouse, KeyboardState keyboard)
{
}
}
Upvotes: 1
Views: 871
Reputation: 6196
Your mesh initialization method is missing something rather important. Namely, calls to glVertexAttribPointer. This method sets where and how your VAO will fetch vertex data. You create buffers and submit data to them, you never set the attribute bindings for the buffers.
It's the attribute bindings that is saved with VAO state and automatically used when binding a VAO, information on buffers being bound to buffer targets like Element array buffer and array buffer are not saved.
Edit:
You seem to be rebinding attributes every time you render, which is not what you're suppose to do, and it's whats causing you problems.
Bind the attributes once in initialization. Then just bind the VAO and render. Simple.
The reason it worked how it did is because you were setting attribute bindings in the material.bind. If the relevant buffers were not bound when you did that, you would get problems. So, it makes sense that it would only work if your buffer is bound, hence why it works when you add the binding line in mesh.bind, which is the call that happens before. But again, you shouldn't be doing this every render call.
Upvotes: 1