I want to store three float values and two byte-values in an interleaved OpenGL vbo. Unfortunately, the rendered data is obviously not correct. When I rendered the same data with two different VBOs, all worked fine, so I don't assume that there is a problem with my shaders.
/*
* 20^3 blocks per chunk, 6 faces per block, 3 vertices per face
* max. every second face can be visible
*/
private static final int MAX_FLOAT_AMOUNT = 20 * 20 * 20 * 6 * 3 / 2;
/*
* 20^3 blocks per chunk, 6 faces per block, 2 bytes per face
* max. every second face can be visible
*/
private static final int MAX_BYTE_AMOUNT = 20 * 20 * 20 * 6 * 2 / 2;
private int dataVboIndex;
protected int vaoId;
protected int indicesCount;
protected boolean isInitialized = false;
public static ByteBuffer dataFloatBuffer = BufferUtils.createByteBuffer(4 * MAX_FLOAT_AMOUNT + MAX_BYTE_AMOUNT);
DefaultChunkVao(int indiciesVboId) {
init();
}
DefaultChunkVao(boolean initialize) {
if(initialize) init();
}
private void init() {
isInitialized = true;
// bind vao
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
//create vbo
dataVboIndex = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, dataVboIndex);
dataFloatBuffer.clear();
dataFloatBuffer.position(4 * MAX_FLOAT_AMOUNT + MAX_BYTE_AMOUNT);
dataFloatBuffer.flip();
// allocate memory
glBufferData(GL_ARRAY_BUFFER, dataFloatBuffer, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4 + 1);
// unbind vao
glBindVertexArray(0);
}
public void updateData(float[] data) {
if(!isInitialized) init();
dataFloatBuffer.clear();
for(int counter = 0; counter < data.length; counter+=0) {
dataFloatBuffer.putFloat(data[counter++]);
dataFloatBuffer.putFloat(data[counter++]);
dataFloatBuffer.putFloat(data[counter++]);
dataFloatBuffer.put((byte) data[counter++]);
dataFloatBuffer.put((byte) data[counter++]);
}
dataFloatBuffer.flip();
glBindBuffer(GL_ARRAY_BUFFER, dataVboIndex);
glBufferSubData(GL_ARRAY_BUFFER, 0, dataFloatBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
this.indicesCount = data.length / 5;
}
The MAX_FLOAT_AMOUNT
and the MAX_BYTE_AMOUNT
constants contains the amount of floats resp. bytes per VBO. Am I right in assuming that I have to multiply the amount of floats with 4 when I determine the capacity of the ByteBuffer
since every float has 4 bytes?
And what did I make wrong that I the my byte values are always 0 in the shader?
EDIT: I was able to reproduce the issue with a simpler example. Here I want to store the position and two bytes in the VBO. In the fragment shader I check if the byte1 value is passed correctly. If so, the shader renders the shape green, else blue. Unfortunately, my shape is rendered blue, hence I assume that the byte1 value is not passed correctly.
vertexShader
#version 400 core
in vec3 position;
in int byte1;
in int byte2;
flat out int p_byte1;
flat out int p_byte2;
void main(void) {
gl_Position = vec4(position, 1);
p_byte1 = byte1;
p_byte2 = byte2;
}
fragmentShader:
#version 400 core
flat in int p_byte1;
flat in int p_byte2;
out vec3 out_color;
void main(void) {
if(p_byte1 == 45) {
out_color = vec3(0, 1, 0);
} else out_color = vec3(0, 0, 1);
}
creating the VAO:
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
final int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
float[] data = {0, 0, 0, 20f, 20f, 1, 1, 1, 20f, 20f, 1, 0, 1, 20f, 20f, 0, 1, 1, 20f, 20f};
ByteBuffer dataBuffer = BufferUtils.createByteBuffer(4 * (3 * 4) + 1 * (2 * 4));
for(int counter = 0; counter < data.length; counter+=0) {
dataBuffer.putFloat(data[counter++]);
dataBuffer.putFloat(data[counter++]);
dataBuffer.putFloat(data[counter++]);
dataBuffer.put((byte) data[counter++]);
dataBuffer.put((byte) data[counter++]);
}
dataBuffer.flip();
glBufferData(GL_ARRAY_BUFFER, dataBuffer, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_UNSIGNED_BYTE, false, 3 * 4 + 2, 3 * 4 + 1);
glBindVertexArray(0);
I was able to find the solution to my question. It is necessary to use glVertexAttribIPointer
instead of glVertexAttribPointer
for integer data types.
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4 + 2, 0);
glEnableVertexAttribArray(1);
glVertexAttribIPointer(1, 1, GL_UNSIGNED_BYTE, 3 * 4 + 2, 3 * 4);
glEnableVertexAttribArray(2);
glVertexAttribIPointer(2, 1, GL_UNSIGNED_BYTE, 3 * 4 + 2, 3 * 4 + 1);