Reputation: 1505
I'm trying to make a water simulation in OpenGL using this tutorial.
It's been going fairly well so far, and I'm trying to make it as efficient as possible, so instead of using glBufferData every frame like I was previously, I'm trying to use glBufferSubData. This is great since the only thing I really need to update is the Y coordinate of the top water bits, so I skip over a lot of data.
However, since the water simulation has droplets, I've run into a problem. It seems you can't add new data when using glBufferSubData, and since the droplets frequently appear and disappear, I can't seem to find a way to add any to the buffer.
I'm using a single VBO for both the water and the droplets since the only other option seems to be using an indexed VAO, but since there aren't any repeated vertices this seems pointless.
Is there another way I don't know of that would help me with this, or am I stuck using glBufferData for all the data forever?
Upvotes: 0
Views: 610
Reputation: 16774
Resizing the buffer is generally a nonexistent concept. You have no idea if there is room right after the buffer in which you need to increase or if the storage is available. All the operations that seem to have this option do in fact check these exceptions and reallocate the buffer if needed.
But in your case the buffer on the GPU is pretty close to the one in the device memory. You can even map the memory to receive the void*
pointer using glMapBuffer
but check the whole procedure doing so.
Combining these facts you are left alone to manage the data in your buffers. If the buffer needs inflating you should create a new one and then copy the old data into it. One of the procedures would be to inflate the buffer by factor of 2 whenever needed:
currentSize = sizof(GLfloat*3*1000)
newSize = currentSize*2
to inflate by 2currentSize
bytes into the new buffer (memcpy
)currentSize
to newSize
But now this was the easy part. Your problem also contains the situation where the chunks of the buffer may be discarded. So you need to track these guys. The are a few ways I can think of:
The thing is that each of them has a drawback. I personally would go with a discardable:
Assume you are working with ObjectiveC/C (if you are using Swift just don't bother). You would have a vertex structure:
struct MyVertex {
GLfloat x,y;
// Add additional values here like color or whatever
GLfloat discarded;
};
Then have s structure for a single segment in your object:
struct Drop {
MyVertex vertices[6]; // or wahtever
}
Now where you set the pointers for the attributes you will need to add another one which is discardable (in glAttributePointer
). For position you are using NULL+offsetof(MyVertex, x)
, for discardable NULL+offsetof(MyVertex, discarded)
. And for stride sizeof(MyVertex)
...
Now in the fragment shader check for discarded value and discard the fragment if it has some value (you can choose whatever value means anything).
So now whenever you are adding a drop you can go through your array in memory and check if one of the drops is discarded and use that one. So you set drops[index].vertices[i].discarded = 0.0
for all the vertices and use the buffer sub data procedure to update this part of the buffer.
When you want to remove it you need to set the discarded to 1.0
(or whatever you want) but also remember to set the vertices to equal value (all 0 for instance). The reason for that is so you reduce the number of fragments generated. It is optimal if you just generate some completely offscreen coordinates.
If possible never use magic numbers, never use fixed values. The sizeof
, offsetof
, struct
and union
should suffice to manage the raw data efficiently. And by using this changing a structure will never break your logic.
Upvotes: 1