VBO order of operations

Okay…so like everybody else, I’m trying to create a “simple” voxel engine.

I’m trying to create a VBO that will draw the entire chunk of 16x16x16 cubes.

My questions are:

  1. FloatBuffer vertexData = BufferUtils.createFloatBuffer(294912);
    Is the above code bad? it’s got 161616*72 slots available for the vertex buffer which means it can store every vertex of every cube.
    Should I be storing this many floats in the same buffer? (it’s my understanding that VBO’s are to Immediate mode as the GPU is to the CPU) which would mean that
    what I’m doing is correct.

  2. what does glGenBuffers() actually do, and when should it be called?
    before the vertices are stored in the float buffer? while they’re being stored? after they’re stored? etc.

  3. what actually happens to the FloatBuffer when it is flipped?
    should it only be flipped once (always)?

  4. what does the following code do?


int vboVertexHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

Any information on any of the above questions would be much appreciated!
*as always, any source code will be supplied upon request :slight_smile:

Thanks!

QuicK

  1. Yes. 1.2MB of data for the same cube? How about just a VBO that holds the data for 1 cube that you render with different offsets 161616 times.

  2. glGenBuffers generates an id for a named location to store data. This location’s memory will be allocated with the call to glBufferData.

  3. When a NIO Buffer is flipped, the limit is set to the position and the position is set to 0. This way, you can read all the data from the beginning to the limit.


int vboVertexHandle = glGenBuffers();                        //Generate ID
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);              //Bind ID
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);   //Store the data in that allocated space
glBindBuffer(GL_ARRAY_BUFFER, 0);                            //Un-bind the ID
  1. That’s no problem, but most of the buffer should be unused in the end. You need to cull (remove) faces that border to other solid blocks so only faces that can actually be visible are stored in VRAM. The size of vertexData should be enough to store even worse case scenarios, but the actual amount of data being uploaded should be pretty low per chunk in 99% of all cases.

  2. glGenBuffers() creates a buffer ID used to refer to data stored on in VRAM on the GPU. You should create a vertex buffer per chunk.

  3. Flipping sets the limit (Kind of like the size of an ArrayList. Note that size != capacity, the array length.) to the current position and resets the position to 0. Basically, you put data into the buffer with buffer.put() and when you’re finished you flip. That way only the actual used part of the array is used thanks to the new limit. If you want to reuse the buffer later, just do a buffer.clear() which resets the limit to the capacity of the buffer.

  4. That code uploads the vertexData buffer to VRAM and stores it there. First line creates a buffer handle. Second binds that buffer handle (they works like texture handles). Third line uploads the data in vertexData to the VBO. 4th line just unbinds the VBO.

No, you really need to batch the cubes together into chunks if you want to render more than a few thousand of them. You also really need to ignore faces that are inside walls/the floor/etc to reduce the number of vertices and triangles as much as possible.

View distance of 400m (1 cube = 1m^3) = Minecraft
With culling: 480 FPS, 150MB of VRAM used
Without: Instant out of VRAM crash

View distance of 100m:
With: 2200 FPS, 40MB of VRAM used
Without: Instant out of VRAM crash

View distance of 50m:
With: 2500 FPS, 30MB of VRAM used
Without: Instant out of VRAM crash

View distance of 25m:
With: 2500 FPS, 30MB of VRAM used
Without: 400 FPS, Crashes after loading around 5 16x16x16 chunks due to out of memory.

Thanks for the replies guys! That really clears up some things that I didn’t know about VBOs!

@ra4king the reason I’m now using FloatBuffer vertexData = BufferUtils.createFloatBuffer(294912); is because I had tried what you suggested prior to posting this, and couldn’t get it to work.

I’ll take what you guys said, and try to fix my chunk code! I’ll update this post after I’ve attempted it! :slight_smile:

Edit:

Okay, so…I’ve tried many things to no avail.

Let me make sure I have things right in my mind. (Note: this is to create a VBO for 16x16x16 cubes)

  1. create the chunk-specific FloatBuffer (vertexData) with enough space to hold all indices of all vertices (294912)
  2. generate the ID for the buffer ([i]glGenBuffers/i) – there should be only one of these right?
  3. run through 3 nested loops (x, y, z) to create the indices
  4. put the indices in vertexData
  5. after the nested loops, flip vertexData
  6. bind the ID generated in step 2, provide the VBO with the vertex data, and unbind the ID generated in step 2
  7. after all of the above steps have been completed, run this every draw tick:

public void draw() {
		
		glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
		glVertexPointer(3, GL_FLOAT, 0, 0L);
		
		glBindBuffer(GL_ARRAY_BUFFER, vboColorHandle);
		glColorPointer(3, GL_FLOAT, 0, 0L);
		
		
		glTranslatef(curx, cury, curz);
		
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);
		glDrawArrays(GL_QUADS, 0, 98304); //98304 derived from 4 vertices per face and 6 faces (4*6) * (16*16*16)
		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisable(GL_CULL_FACE);
		
	}

And…as usual I feel extremely dumb because I found out my problem as I was writing this out.
M issue was in glDrawArrays()…I was only allowing enough indices for 1 cube.

I decided to go ahead and post this in case anybody else finds it useful :slight_smile: thanks for the help guys! I still learned a good bit about VBOs from this :slight_smile: