Vertex buffer object (VBO)
A Vertex Buffer Object (VBO) is an OpenGL buffer object for buffering vertex data to VRAM so as to make rendering faster.
There are different types of VBO, here we will consider GL_ARRAY_BUFFER type.
create VBO
If you manage native memory yourself, you can pre-allocate a huge block and create several buffers from it. In LWJGL MemoryUtil and MemoryStack classes do it.
fun createVBO(data: FloatArray): Int {
MemoryStack.stackPush().use { stack ->
val idVbo = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, idVbo)
val fb = stack.mallocFloat(data.size)
fb.put(data).flip()
glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW)
return idVbo
}
}
public static int createVBO(float[] data) {
try (MemoryStack stack = MemoryStack.stackPush()) {
int idVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, idVbo);
FloatBuffer fb = stack.mallocFloat(data.length);
fb.put(data).flip();
glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW);
return idVbo;
}
}
GlUtils.createVBO = function(gl, array){
const idVbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, idVbo);
gl.bufferData(gl.ARRAY_BUFFER,
new Float32Array(array),
gl.STATIC_DRAW);
return idVbo;
}
private var FLOAT_BUFFER: FloatBuffer = ByteBuffer.allocateDirect(100 * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer()
private val ID_ARRAY = intArrayOf(0)
fun createVBO(data: FloatArray): Int {
glGenBuffers(1, ID_ARRAY, 0)
val idVbo = ID_ARRAY[0]
glBindBuffer(GL_ARRAY_BUFFER, idVbo)
FLOAT_BUFFER.put(data).position(0)
glBufferData(GL_ARRAY_BUFFER, data.size * 4, FLOAT_BUFFER, GL_STATIC_DRAW)
return idVbo
}
vertex attributes
After creating VBO you need specify what type of data it contains. It can be any vertex attributes like coordinates, color, etc.
One VBO may contains several attributes. For example, the following function allows you to specify coordinates, color, and texture coordinates, which are packed into sequential order.
fun bindAttributes(idVBO: Int, numCoords: Int, numColorComponents: Int, texCoord: Boolean) {
glBindBuffer(GL_ARRAY_BUFFER, idVBO)
// size of float is 4
val stride = 4 * (numCoords + numColorComponents + if (texCoord) 2 else 0)
if (numCoords > 0) {
glEnableVertexAttribArray(A_LOCATION_COORDS)
glVertexAttribPointer(
A_LOCATION_COORDS,
numCoords, GL_FLOAT, false,
stride, 0)
}
if (numColorComponents > 0) {
glEnableVertexAttribArray(A_LOCATION_COLORS)
glVertexAttribPointer(
A_LOCATION_COLORS,
numColorComponents, GL_FLOAT, true,
stride, 4 * numCoords)
}
if (texCoord) {
glEnableVertexAttribArray(A_LOCATION_TEXCOORDS)
glVertexAttribPointer(
A_LOCATION_TEXCOORDS,
2, GL_FLOAT, false,
stride, 4 * (numCoords + numColorComponents))
}
glBindBuffer(GL_ARRAY_BUFFER, 0)
}
public static void bindAttributes(int idVBO, int numCoords, int numColorComponents, boolean texCoord) {
glBindBuffer(GL_ARRAY_BUFFER, idVBO);
// size of float is 4
int stride = 4 * (numCoords + numColorComponents + ((texCoord) ? 2 : 0));
if (numCoords > 0) {
glEnableVertexAttribArray(A_LOCATION_COORDS);
glVertexAttribPointer(A_LOCATION_COORDS,
numCoords, GL_FLOAT, false,
stride, 0);
}
if (numColorComponents > 0) {
glEnableVertexAttribArray(A_LOCATION_COLORS);
glVertexAttribPointer(A_LOCATION_COLORS,
numColorComponents, GL_FLOAT, true,
stride, 4L * numCoords);
}
if (texCoord) {
glEnableVertexAttribArray(A_LOCATION_TEXCOORDS);
glVertexAttribPointer(A_LOCATION_TEXCOORDS,
2, GL_FLOAT, false,
stride, 4L * (numCoords + numColorComponents));
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
GlUtils.bindAttributes = function(gl, idVbo,
numCoords,
numColorComponents,
texCoord) {
gl.bindBuffer(gl.ARRAY_BUFFER, idVbo);
// size of float is 4
const stride = 4 * (numCoords + numColorComponents + ((texCoord) ? 2 : 0));
const A_LOCATION_COORDS = 0;
const A_LOCATION_COLORS = 1;
const A_LOCATION_TEXCOORDS = 3;
if (numCoords > 0) {
gl.enableVertexAttribArray(A_LOCATION_COORDS);
gl.vertexAttribPointer(
A_LOCATION_COORDS, numCoords,
gl.FLOAT, false, stride, 0);
}
if (numColorComponents > 0) {
gl.enableVertexAttribArray(A_LOCATION_COLORS);
gl.vertexAttribPointer(
A_LOCATION_COLORS, numCoords,
gl.FLOAT, false, stride, 4 * numCoords);
}
if (texCoord) {
gl.enableVertexAttribArray(A_LOCATION_TEXCOORDS);
gl.vertexAttribPointer(
A_LOCATION_TEXCOORDS, numCoords,
gl.FLOAT, false, stride, 4 * (numCoords + numColorComponents));
}
}
drawing VBO
To draw VBO you must just activate it, then invoke
// draw white quad (4 vertices)
glBindBuffer(GL_ARRAY_BUFFER, idVbo)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
OpenGL 3.0 may not to draw VBO without VAO. So, in the LWJGL example I used OpenGL 2.0 and old shaders.
#version 120
attribute vec4 vCoord;
varying vec4 exColor;
uniform mat4 matrix;
void main() {
gl_Position = matrix * vCoord;
exColor = vec4(1.0,1.0,1.0,1.0);
}
#version 120
varying vec4 exColor;
void main() {
gl_FragColor = exColor;
}
You can download full sources of quad with solid color on GitHub.