Sorry for not answering for so long, but it turns out the problem kind of fixed itself(?) or i fixed it without knowing it… anyways, i just kept trying things out, played here and there and then at one point i wanted to give up and changed everything back to how (i thought) it was and then all of a sudden everything worked perfectly. I still dont know what made the difference. And yes, i am checking for opengl errors, but i have not been getting any.
But it seems to be the way i allocate the buffer in OpenGL, because this is now different from what i have posted here before:
//...get uniform block index and bind it to uniform buffer binding array index 0...
glBindBuffer(GL_UNIFORM_BUFFER, materialBuffer);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, materialBuffer);
glNamedBufferStorage(materialBuffer, sizeof(Material)*allMaterials.size(), &allMaterials[0], GL_MAP_READ_BIT);
But i still have not grasped the whole concept behind uniform buffers, which gives me trouble with my light uniform array now. I understand that for every shader program there is an array of binding points for GL_UNIFORM_BUFFER which is GL_MAX_UNIFORM_BUFFER_BINDINGS in size. These bindings are used to link glsl uniform blocks to buffers in OpenGL.
So appearently this is all there is to it; i upload data to a buffer, link that buffer to a binding Index (glBindBufferBase) and then i can link a glsl uniform block to that binding point and then i have access to the data in the buffer from that uniform block.
This i how far i can get everything to work. But then of course there is data layout aswell. And this is what i have problems with with my light data. to get rid of any kind of padding and to also be able to manage different types of lights (directional, point, spot) more performance friendly, i have decided to create an array of floats which holds all the light data for every kind of lightsource in my application. Then i have an array of Light structs which contain indices into the float array. and if i want to get the color of a light i just say vec3(lightData[light.colorIndex], lightData[light.colorIndex + 1], lightData[light.colorIndex + 2]); in the shader. because there should be no padding… (array of floats…right?)… i thought this will work perfectly, but appearently there is still something i dont know about. I am getting data into the lightData buffer, but it is not layed out correctly. When i acces the lightData array with hardcoded indices, some values are correct, others are 0, and others seem to be undefined, huge or negative garbage values.
What is new about this (compared to the material buffer), is that this buffer needs to be streamed to and this might be where the data corruption is happening.
So this is how i do the lights right now:
OpenGL:
//Here i allocate the buffer space and link them and the uniform blocks to their binding points.
void initOpenGLBuffer(){
//...
ShaderProgram::use("deferredShader_lStage");
int block_index = glGetUniformBlockIndex(ShaderProgram::currentProgram->ID, "LightDataBuffer");
glUniformBlockBinding(ShaderProgram::currentProgram->ID, block_index, 1);
block_index = glGetUniformBlockIndex(ShaderProgram::currentProgram->ID, "LightIndexBuffer");
glUniformBlockBinding(ShaderProgram::currentProgram->ID, block_index, 2);
ShaderProgram::unuse();
//Lightbuffers
glBindBuffer(GL_UNIFORM_BUFFER, lightDataBuffer);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, lightDataBuffer);
glNamedBufferData(lightDataBuffer, sizeof(float)*11*App::MAX_LIGHTS_COUNT, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, lightIndexBuffer);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, lightIndexBuffer);
glNamedBufferData(lightIndexBuffer, sizeof(unsigned int)*3*App::MAX_LIGHTS_COUNT, nullptr, GL_DYNAMIC_DRAW);
}
// i call this every frame when all my light data is updated to upload the updated data to the buffers. for this i invalidate the old buffer ( which should stay around for later use, according to the concept of orphaning) and then i refill the entire buffer
void uploadLightData(){
glInvalidateBufferData(lightDataBuffer);
glInvalidateBufferData(lightIndexBuffer);
glBindBuffer(GL_UNIFORM_BUFFER, lightDataBuffer);
//one light can at max contain 11 floats in my implementation
glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(float) * 11 * App::MAX_LIGHTS_COUNT, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 11 * App::MAX_LIGHTS_COUNT, &allLightData[0], GL_DYNAMIC_DRAW);
//unmapping the buffer throws an opengl error string "invalid operation"
//glUnmapBuffer(GL_UNIFORM_BUFFER);
checkOpenGLErrors("OpenGL::uploadLightData()1:");
// the index array should be ignored right now, because i am still hardcoding the indices in the shader
glBindBuffer(GL_UNIFORM_BUFFER, lightIndexBuffer);
glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(unsigned int) * 3 * App::MAX_LIGHTS_COUNT, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
glBufferData(GL_UNIFORM_BUFFER, sizeof(unsigned int) * 3 * App::MAX_LIGHTS_COUNT, &lightIndices[0], GL_DYNAMIC_DRAW);
//unmapping the buffer throws an opengl error string "invalid operation"
//glUnmapBuffer(GL_UNIFORM_BUFFER);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
checkOpenGLErrors("OpenGL::uploadLightData()2:");
}
And in glsl i have declared the uniform blocks like this
//not in use yet
struct Light{
unsigned int baseIndex; // index to 4 floats; color and brightness
unsigned int positionIndex; // index to 3 floats
unsigned int frustumIndex; // index to 4 floats; frustum direction and angle
};
//notice the missing layout(std140), i have tried it with it, but no success. i actually dont want to use it, because i am thinking with an array of only floats i dont need any automatic layout
uniform LightDataBuffer{
float lightData[11*MAX_LIGHT_COUNT];
};
uniform LightIndexBuffer{
Light lights[MAX_LIGHT_COUNT];
};
void main(){
//color for the first light
vec3 lightColor = vec3(lightData[0], lightData[1], lightData[2]);
...
}
I guess i will just screw around some more again and hope that the problem fixes itself again. i am betting its just one teenytiny command i am missing that changes everything…