is this how to update the data in a VBO.

Started by zevrix, February 09, 2014, 22:37:22

Previous topic - Next topic

zevrix

I am working on a way to create a VBO that updates every time the character moves (this can happen at any time).  I am just wondering if this would be the correct code to do that without leaving old data in the graphics card or RAM every update.

public void initVBO(Vector3f[] vertices)
{
	VBOBuffer = Util.createFlippedBuffer(vertices);    //create a new flipped buffer with the initializing vertices 
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, VBOBuffer, GL_DYNAMIC_DRAW);    //dynamic draw because it will update often
}
	
public void updateVBOData(Vector3f[] vertices)
{
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferSubData(GL_ARRAY_BUFFER, 0, Util.updateFlippedBuffer(VBOBuffer, vertices));      //replace data in VBO with new data
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
}
	
public void draw()
{
	glEnableVertexAttribArray(0);            //dont actually know what this does. i was told to use it in a tutorial.. if somone can explain that would be great :)
	glEnableClientState(GL_VERTEX_ARRAY);
		
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, DATA_SIZE, GL_DYNAMIC_DRAW);      //because it will be drawn often 

	glDrawArrays(GL_TRIANGLES, 0, 
				BLOCK_SIZE_X * BLOCK_SIZE_Y *
				BLOCK_AMT_X * BLOCK_AMT_Y * DATA_SIZE);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

	glDisableClientState(GL_VERTEX_ARRAY); 
		
	glDisableVertexAttribArray(0);
}

public static FloatBuffer updateFlippedBuffer(FloatBuffer buffer, Vector3f[] vectors)
{ 
	buffer.clear();                      //clear buffer (it says this doesn't delete the data in the javadoc is this still going to remove the old data?)
	buffer = BufferUtils.createFloatBuffer(vectors.length * 3);   //create new buffer
	for(int i = 0; i < vectors.length; i ++)
	{
		buffer.put(vectors[i].getX());
		buffer.put(vectors[i].getY());
		buffer.put(vectors[i].getZ());
	}
	buffer.flip();       //flip the buffer (does buffer.clear() un-flip the buffer?, does this need to be called here still?)
		
	return buffer;
}

Cornix

Not quite perfect but on its way.

The biggest problem I see right now is the fact that you create a new ByteBuffer in every single frame.
This is definitely not the fastest way to do it, although its probably going to work.

Just keep re-using the same buffer. There is no need to create a new one.
The next point, when talking performance, is the fact that you insert values into your buffer in piecemeal. The fastest way to write data to a ByteBuffer in java is the bulk put methods.
This can actually do a real lot; I tested this very thoroughly when I was starting with lwjgl.

The fastest way to keep your vertices is to have them all in one big float array and simply put that whole array into the ByteBuffer at once.


Now to answer some of your questions:
Quotebuffer.clear();                      //clear buffer (it says this doesn't delete the data in the javadoc is this still going to remove the old data?)
The clear method in the ByteBuffer will only change its position and limit to the default values. Those are both int variables of the buffer.
You can not manually "delete" the data on the video RAM. If you want your graphics card to free memory you have to call glDeleteBuffers(vboID).

Quotebuffer.flip();       //flip the buffer (does buffer.clear() un-flip the buffer?, does this need to be called here still?)
The flip method simply swaps the position and the limit of the buffer. The clear method does not matter here because you have been creating a new buffer anyways. (which is bad by the way)
The flip method should be called everytime when you are about to put data into the buffer after reading before and when you are about to read data from the buffer after writing.
Since you just wrote data to the buffer before and you are going to read the buffer later the flip is correct here.

QuoteglEnableVertexAttribArray(0);            //dont actually know what this does. i was told to use it in a tutorial.. if somone can explain that would be great :)
It enables the generic vertex attribute with the ID == 0.
Just read up the documentation on generic vertex attributes.


QuoteglBufferData(GL_ARRAY_BUFFER, DATA_SIZE, GL_DYNAMIC_DRAW);      //because it will be drawn often
Dont call this method within your draw() method. The method glBufferData will WRITE data to the buffer. You dont want that to happen within this method, you have the method updateVBOData(...) for this purpose.


This is how your code could look like:
public void initVBO(Vector3f[] vertices)
{
	VBOBuffer = Util.createFlippedBuffer(vertices);    //create a new flipped buffer with the initializing vertices 
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, VBOBuffer, GL_DYNAMIC_DRAW);    //dynamic draw because it will update often
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}
	
public void updateVBOData(Vector3f[] vertices)
{
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferSubData(GL_ARRAY_BUFFER, 0, Util.updateFlippedBuffer(VBOBuffer, vertices));      //replace data in VBO with new data
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}
	
public void draw()
{
	glEnableClientState(GL_VERTEX_ARRAY);
		
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	glDrawArrays(GL_TRIANGLES, 0, 
				BLOCK_SIZE_X * BLOCK_SIZE_Y *
				BLOCK_AMT_X * BLOCK_AMT_Y * DATA_SIZE);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

	glDisableClientState(GL_VERTEX_ARRAY); 
}

public static FloatBuffer updateFlippedBuffer(FloatBuffer buffer, Vector3f[] vectors)
{ 
	buffer.clear();
	for(int i = 0; i < vectors.length; i ++)
	{
		buffer.put(vectors[i].getX());
		buffer.put(vectors[i].getY());
		buffer.put(vectors[i].getZ());
	}
	buffer.flip();
	return buffer;
}

broumbroum

If it happens to update as frequently as the character moves on the map, then I'll keep everything in a fast accessible memory. The graphics driver would do all the cache management for you. Updating the VBO can be painful.
As @cornix : "Just keep re-using the same buffer. There is no need to create a new one. " Because the *Buffer of vertices are stored in RAM, which is led out by the CPU-cycles (not the GPU's). Every time the GPU needs to display a frame, it would need another CPU-cycle, which is not desirable. 
I 'd try the following :

Find a way to get your data from the File. From that file, load gradually (tile-to-tile) all the vertices data into separate VBO items.
This should have an improve on the frame rate.

Another idea maybe : to bind many VBOS also costly, since the Textures are to load next. One VBOs able to handle all your data (but it might not exceed a certain amount of giga/megabytes see OpenGl limitations), and point directly to the offsets within the VBO indices. Some posts on Stack exchange can help to understand with pieces of codes.

Finally, bind the selected VBOs for your world map. To simulate a move onto the map, like in a movie, we could change the drawn picture frame, from VBO chunks, just on the fly, behind the scenes . Another post on game stack exchange.

Anyway, if you were looking for a 3D map scene generator, there'd be plenty of different engines ready to use out of the box, some accessible by open source.

Good luck! :o

zevrix

To be a bit more precise with the background info im making a map that's split into blocks to avoid loading large amounts of map into the RAM at any 1 time, and what i am trying to do is change the data in the vbo to the next block it should render.  (all blocks are the same size, 128 X 128 vertices, this means there is 442,368 floats in the 9 VBO's at any given time (plus texture data and what not)).  following the picture provided, then the player moves, so does the camera, once the player moves into another block, the game unload the blocks that are out of the 3 X 3 grid and loads the blocks that should be replacing them, all while shifting the blocks over to make room for the new blocks.

image: www(dot)imgur(dot)com/MRTyMEW