I've been writing an experimental app in which I render 100 chunks of 16x16x16 cubes using VBO. I'm doing this because a dozen people have praised beyond measure VBO, and have told me that it's much better performing than the per-chunk display lists I'm using in my actual Minecraft-style game.
It's been a painful process, trying to adapt many poorly written tutorials that only focus on a single cube/triangle into something that can handle the amount of drawing I need. I'm still not at all convinced that VBOs are better for my game than display lists.
For the most part, I've finally tweaked the code so that my interleaved VBO data is built only once (when the chunk loads) and then each render call, the buffer ID is bound and glDrawArrays is called.
I'm slowly increasing the quantity of blocks/chunks in this experimental app to see how performance handles. In the actual game, it'll have to handle 16x16x128 blocks in every chunk, with at most 20x20 chunks loaded. Roughly 60% of those will be solid blocks that are rendered, so maybe 8 million blocks. That renders without much issue using the display list method I started with.
However, even though I have VBO render performance within tolerable levels now, I can't generate a radius of 10 chunks without hitting a memory limit:
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:658)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
at org.lwjgl.BufferUtils.createByteBuffer(BufferUtils.java:60)
at org.lwjgl.BufferUtils.createFloatBuffer(BufferUtils.java:110)
at com.helion3.opengl.rendering.TextureQuadRenderer.<init>(TextureQuadRenderer.java:25)
at com.helion3.opengl.shapes.Chunk.<init>(Chunk.java:13)
at com.helion3.opengl.shapes.World.<init>(World.java:18)
at com.helion3.opengl.Game.start(Game.java:90)
at com.helion3.opengl.Launcher.main(Launcher.java:19)
I'm pretty confident that my buffers are setup with the right counts needed. I call:
BufferUtils.createFloatBuffer( using 192 floats per cube (3 vertices, 3 colors, 2 texture coords multiplied by six faces and 4 vertices per face) multiplied by 4096 - the number of blocks in the chunk test.
Now in the real game, I'm not rendering the block faces that aren't exposed to air - but even if I do that in this test application, I'm still only rendering 16x16x16 blocks.
How can I better manage the VBO memory? My VBO test app rendering code, chunk code
At which point do VBOs shine they way everyone's been selling them as? lol
P.S. I guess I'll dive into instancing now, see how that helps.
GLubyteuses 1/4 the storage. Also I am not sure why you are running out of Java memory doing this; VBOs allocate memory in an address space managed by the display driver... VRAM for all intents and purposes. If you use VBOs properly you should not be appreciably increasing the memory Java itself has to manage for your application, this means freeing the originalByteBufferafter you send the data to GL. - Andon M. Colemanclearing the original ByteBuffer - setting it tonullseems to solve the memory prob, but the performance with 20x20 chunks is back down to horrible. I'm now at the scale though where I really ought to disable rendering the full cube if it's not exposed. Pretty soon I'll have my original game... lol - helion3structs which are composed of a mix ofGLfloatandGLubyte, the way it should be. You can still mix-and-matchGLubyteandGLfloatin an interleaved VBO in Java, but you need to use aByteBufferand pack your floating-point components into it as 4 bytes each and color components as 1 byte each. It is more complicated for sure, but it is the proper way of handling vertex arrays with color. - Andon M. ColemanbyteBuffer.asFloatBuffer()for the float values? - helion3