I need to update my mesh with new vertices. I create the VBO as such (initially it gets created with only one vertex in it):
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[]{0}).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
then I want to update the VBO buffer and write new vertices into it. Note that I do create VBO to have enough space for my new vertices, and I do control that it doesn't get overfilled. I also control how many elements I draw with each render call, so I don't draw the empty 0/0/0 vertices.
My problem is, this code WORKS:
public void updateVBO(float[] vertices, int[] indices, int size)
{
if (meshType == 1)
{
lineCount = size;
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
try
{
//System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
//float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vertices.length); // !!! Must Be manually freed!
subDataF.put(vertices).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, subDataF, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
//int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(indices.length); // !!! Must Be manually freed!
subDataI.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, subDataI, GL_STATIC_DRAW);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
so when I pass the entire vertices array, and re-allocate VBO memory from scratch - it draws exactly what I need it to. However I would like to use glBufferSubData, so that I don't re-allocate the momory each time I add new vertex. And this code DOESN'T WORK:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, position * 3 * 4, subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, position * 4, subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
Also I'm aware it's not optimized the way I create the floatbuffer and intbuffer, I just want to get it to work before I clean this up. I was trying a bunch of things, so the last piece of code is weird because of that.
Still, I don't understand what I'm doing wrong. I did check that I pass all the data correctly, and that the position (and offset) seem to be calculated how they should be. And it just doesn't draw anything, while when I use glBufferData it does.
Could someone explain where I'm making a mistake?
After all suggestions, here's what I end up with, but it still doesn't work at all:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
System.out.printf("Adding vertex (%f, %f, %f) to position %d\n",vertex.x,vertex.y,vertex.z,position);
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(3); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(1); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindVertexArray(vaoID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
I did check that VAO ID is correct.
Just as I thought, it was something stupid, and not at all connected to VAO binding and such.
The thing is, when I create VBO initially, I do it like this:
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
I assumed that because I allocate buffer for size*3 floats, it will be of that size, and when I put it in the VBO - it will allocate size*3*4 bytes, i.e. enough for size*3 floats.
Turns out Nope! Because I put only one vertex (3 floats) into the buffer - it will allocate only that amount of space. So when I later try to use glBufferSubData - it only has spaces for 3 floats on the GPU, and naturally doesn't put the values where I need them. I'm actually surprised it doesn't flat-out crash on me.
To fix this, at the moment I did this instead:
// Vertices VBO generation
...
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
...
So basically I'm manually putting an empty array into the FloatBuffer, and that ensures that the buffer is the right size.
Here's the result: Constructor:
public Mesh(float[] vertex, int size)
{
texture = null;
meshType = 1; //will draw lines
FloatBuffer verticesBuffer = null;
IntBuffer indicesBuffer = null;
int vboID;
try
{
vertexCount = size;
vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
vboIDList = new ArrayList<>();
// Vertices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
verticesBuffer = MemoryUtil.memAllocFloat(size * 3); // !!! Must Be manually freed!
verticesBuffer.put(vertex).put(new float[size*3 - 3]).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vertexAttrArrCount += 1;
// Indices VBO generation
vboID = glGenBuffers();
vboIDList.add(vboID);
indicesBuffer = MemoryUtil.memAllocInt(size); // !!! Must be manually freed!
indicesBuffer.put(new int[size]).flip(); // I need the first element 0 anyway
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
// unbinding
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
finally
{
if (verticesBuffer != null)
{
MemoryUtil.memFree(verticesBuffer); // Freeing vertex buffer
}
if (indicesBuffer != null)
{
MemoryUtil.memFree(indicesBuffer); // Freeing indices buffer
}
}
}
And then updating:
public void addVertex(Vector3f vertex, int position)
{
if (meshType == 1)
{
FloatBuffer subDataF = null;
IntBuffer subDataI = null;
int vboID;
lineCount = position+1;
try
{
vboID = vboIDList.get(0);
float[] vert = new float[]{vertex.x, vertex.y, vertex.z};
subDataF = MemoryUtil.memAllocFloat(vert.length); // !!! Must Be manually freed!
subDataF.put(vert).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ARRAY_BUFFER, (long)(position * 3 * 4), (FloatBuffer)subDataF);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
vboID = vboIDList.get(1);
int[] index = new int[]{ position };
subDataI = MemoryUtil.memAllocInt(index.length); // !!! Must Be manually freed!
subDataI.put(index).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, (long)(position * 4), (IntBuffer)subDataI);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
finally
{
if (subDataF != null)
{
MemoryUtil.memFree(subDataF);
}
if (subDataI != null)
{
MemoryUtil.memFree(subDataI);
}
}
}
}
And it works. Do note that the code is a bit dirty, I didn't clean it up before posting an answer.