Is there a way to modify the content of a vbo while it has been binded.
Or is there a better way to modify the size of a rectangle on the run?
How big is your VBO that there is a difference to just rendering it and modifying it then?
Yes it’s possible to modify a VBO but before that, see the VBO drawing hints. There are constants for drawing which also give some hints to the opengl rendering engine.
GL_STATIC_DRAW // The VBO will be created once and drawn many times
GL_STREAM_DRAW // The VBO will be updated every frame
GL_DYNAMIC_DRAW // The VBO will be updated n times and is drawn n times
Then create the VBO as you normally would and you can update the contents with the [icode]glBufferSubData()[/icode] function. It’s syntax is
/**
* Updates a subset of a buffer object's data store. It redefines some or
* all of the data store for the buffer object currently bound to target. Data
* starting at byte offset offset and extending for size bytes is copied to the
* data store from the memory pointed to by data.
*
* @param target Specifies the target buffer object.
* @param offset Specifies the offset into the buffer object's data store
* where data replacement will begin, measured in bytes.
* @param data A FloatBuffer containing the data of the VBO
*/
public static void glBufferSubData(int target, int offset, FloatBuffer data);
To replace the entire VBO, you can use the following, setting the offset to 0.
glBufferData(GL_ARRAY_BUFFER, 0, data);
This updates the entire VBO.
The glBufferSubData method works similarly to glBufferData.
You might also want to look at the usage hint you provide when initially uploading data using glBufferData (the last argument).
So when the first buffer is created it is bound with GL_STREAM_DRAW. And i created the second buffer wit hthe data i want to be updated. But it seems like glBufferSubData is not changing the data out. Nothing changes.
glBufferSubData cannot be put into update method, cause update thread calls the update method out and update thread contains no GL syntax.
public void renderInit() {
renderInitStart();
vboVertexID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@Override
public void renderInitStart() {
if(!textured){
setTexture();
}
Texture tex = RenderThread.spritesheet.getTex();
texture = tex.id;
vboTexVertexID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTexVertexID);
glBufferData(GL_ARRAY_BUFFER, texVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@Override
public void renderDraw() {
glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
glBufferSubData(GL_ARRAY_BUFFER,0,Vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_QUADS, 0, 24);
glDisable(GL_BLEND);
}
@Override
public void update() {
if(currentFuel != player.getFuel()){
currentFuel = player.getFuel();
float[] vertex = {
width*x,height*y+10,width*x+hull*(player.getFuel()/100),height*y+10,width*x+hull*(player.getFuel()/100),height*y,width*x,height*y,
width*x,height*y+44,width*x+fuel*(player.getFuel()/100),height*y+44,width*x+fuel*(player.getFuel()/100),height*y+34,width*x,height*y+34
};
Vertices.put(vertex);
Vertices.rewind();
}
}
It’s tricky to work out what the problem is without seeing the ‘loop’ where these methods are being invoked or understanding what you’re trying to achieve.
Is renderInitStart only invoked once? If so, why is the glBufferSubData call there? If it is called on every frame then you will need to move the glBufferSubData call after you’ve bound the VBO (I think calling methods on the default VBO is undefined but don’t quote me on that).
i.e.
init:
- allocate the buffer
- bind
- glBufferData to initialise VBO (if required)
on each frame:
- bind the VBO
- glBufferSubData to update the VBO with the new vertices
- draw it
after each frame:
- update the vertices
I’m looking for an answer to this too. My vertices and textures are fixed and I have VBOs bound for them. However, the colors change possibly every frame.
How does glBufferSubData compare to glMapBuffer?
well… i dont know about glMapBuffer. But the glBufferSubData: create the VBO normally except in the gl glBufferData you but GL_STREAM_DRAW instead of GL_STATIC_DRAW. and then when you have the now content ready for the buffer you just. glBindBuffer(GL_ARRAY_BUFFER, BufferID);
glBufferSubData(GL_ARRAY_BUFFER, offset, buffer with new content);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Only problem that remains is that i have to change the entire buffer. When i try to change from the offset it doesent draw properl anymore…
This is what I discovered last night. The following are scala snippets but should be easy to follow.
My original vertex data are stored in java.nio buffers:
private val vertices: java.nio.FloatBuffer
private val textures: java.nio.FloatBuffer
private val colors: java.nio.ByteBuffer
Assuming you have somewhere to store the int handles to your VBOs (I have 3, one for vertices, textures, and colors):
private var vHandle: Int = -1
private var tHandle: Int = -1
private var cHandle: Int = -1
Create your buffers just once and upload your data to the graphics card.
val ib: IntBuffer = BufferUtils.createIntBuffer(3) // 3 buffers needed
glGenBuffers(ib)
vHandle = ib.get(0)
tHandle = ib.get(1)
cHandle = ib.get(2)
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glBufferData(GL_ARRAY_BUFFER, textures, GL_STATIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glBufferData(GL_ARRAY_BUFFER, colors, GL_DYNAMIC_DRAW) // dynamic as this could change
glBindBuffer(GL_ARRAY_BUFFER, 0) // unbind
Now in your draw method you can paint statically which is the fastest:
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glVertexPointer(3, GL_FLOAT, 0, 0)
glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glTexCoordPointer(2, GL_FLOAT, 0, 0)
glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0)
glDrawArrays(GL_QUADS, 0, 4 * capacity) // 4 vertices per quad
glBindBuffer(GL_ARRAY_BUFFER, 0)
But if values change, i.e. you’ve directly modified the values in vertices, textures, and colors, you can intentionally do an upload. Here’s an example of me uploading the colors also during the draw/render phase:
glBindBuffer(GL_ARRAY_BUFFER, vHandle)
glVertexPointer(3, GL_FLOAT, 0, 0)
glBindBuffer(GL_ARRAY_BUFFER, tHandle)
glTexCoordPointer(2, GL_FLOAT, 0, 0)
glBindBuffer(GL_ARRAY_BUFFER, cHandle)
glBufferSubData(GL_ARRAY_BUFFER, 0, colors) // upload colors
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0)
glDrawArrays(GL_QUADS, 0, 4 * capacity)
glBindBuffer(GL_ARRAY_BUFFER, 0)
At some point in time you need to free the VBOs but that is only when you’re done with them and not necessarily every frame.
val ib: IntBuffer = BufferUtils.createIntBuffer(3)
ib.put(0, vHandle)
ib.put(1, tHandle)
ib.put(2, cHandle)
glDeleteBuffers(ib)
On my system, I can render a frame in about 1.5 msec with pure static VBOs. If I need to upload the colors on 160000 quads, the render jumps up to around 2.0 msec. Yes technically, I am not modifying the VBO purely in video memory and instead I’m uploading an entire data set. However, the performance hit appears negligible and note that depending on how I manage things, I may not need to upload data every frame.
[edit] use glBufferSubData instead of glBufferData on upload
Always use [icode]glBufferSubData[/icode] to update the entire data. It just updates the data whereas [icode]glBufferData[/icode] will delete the previous data, allocate new memory and then copy the data. With [icode]glBufferSubData[/icode] there is some increase in performance since the same memory will be reused.
I assume you meant [icode]glBufferData[/icode] in the above (where I’ve struck-out).
Good to know. I’ll give glBufferSubData a try and report back.
Thanks SHC for the tip. Using glBufferSubData reduced render from around 2.3 msec down to 1.6 msec. Approximately 25% less time!
OP, did you manage to get your code working?
Yes the code is working. Now i just need to torture the guy who built the threading system :D, its a mess :D.
Yeah. Was sleepy so a typo. Thanks.
This is not entirely true. glBufferData() doesn’t immediately delete the previous data since the GPU might still be using it. However, you’re right that it reallocates the memory on each call. This is called orphaning and it has some useful characteristics. Let’s say you have a small VBO which you update multiple times per frame. In this case, glBufferSubData() and glMapBuffer() will have terrible performance since each time you update the buffer you basically stall the entire OpenGL pipeline since the GPU has to finish using the old data before it’s overwritten. If you instead use glBufferData(), the driver is smart enough to not immediately delete the old buffer and the driver may keep multiple internal buffers for each call to glBufferData(). In this case, there is no stall since the driver isn’t forced to overwrite the old data of the buffer and can just keep the old buffers in memory and deallocate them when they no longer have a use. In the case of a buffer being updated only once per frame, the overhead of glBufferData() is a bad thing and glBufferSubData() or (even better) glMapBuffer() is preferred to glBufferData() like you said.