3

I am using JOGL to develop small OpenGL applications in Java. I am facing the following issue: I have a Uniform Buffer Object "Light" declared in the fragment shader as follows:

struct PerLight
{
    vec4 cameraSpaceLightPos;
    vec4 lightIntensity;
};

const int numberOfLights = 4;

uniform Light
{
    vec4 ambientIntensity;
    float lightAttenuation;
    PerLight lights[numberOfLights];
} Lgt;

As I understand, the only not straightforward part when putting data inside the UBO is that the float "lightAttenuation" will need to be padded with 3 floats.

I put the data in my buffer as follows (all values except lightAttenuation are arrays with 4 float values):

gl.glBindBuffer(GL2.GL_UNIFORM_BUFFER, lightUniformBuffer[0]);

    FloatBuffer buffer = Buffers.newDirectFloatBuffer(2 * (2 + DynamicRangeLights.NUMBER_OF_LIGHTS * 2) * 4);
    buffer.put(lightData.ambientIntensity.getArray());
    buffer.put(new float[] { lightData.lightAttenuation, 0.0f, 0.0f, 0.0f });
    for (int i = 0; i < 4; ++i) {
        buffer.put(lightData.lights[i].cameraSpaceLightPos.getArray());
        buffer.put(lightData.lights[i].lightIntensity.getArray());
    }
    buffer.rewind();

    gl.glBufferSubData(GL2.GL_UNIFORM_BUFFER, 0, sizeLightBlock, buffer);

But the result I get is wrong: the colors and intensities of the lights are completely off.

If I rewrite the UBO in my fragment shader as follows, everything works fine:

uniform Light
{
    vec4 ambientIntensity;
    float lightAttenuation;
    vec4 cameraSpaceLightPos0;
    vec4 lightIntensity0;
    vec4 cameraSpaceLightPos1;
    vec4 lightIntensity1;
    vec4 cameraSpaceLightPos2;
    vec4 lightIntensity2;
    vec4 cameraSpaceLightPos3;
    vec4 lightIntensity3;
} Lgt;

According to me, the two UBOs should receive the same data and display the same result, but apparently I am wrong. What is the difference between these two UBOs, and how should I buffer the data in the first one to get the same result as the second one?

Edit: I forgot to mention it, but I use in my shaders

layout(std140) uniform;

So if I am not wrong, all uniforms use the std140 layout.

MRenauld
  • 35
  • 5
  • That looks pretty odd. I've had a look through [Uniform and Shader Storage Block Layout Qualifiers](https://www.opengl.org/registry/doc/GLSLangSpec.4.40.pdf) which seems to contain most of the info about alignment and nothing jumps out at me. It'd be interesting to [query the offsets for those uniforms](http://stackoverflow.com/q/440144/1888983) and see where its actually putting things. – jozxyqk Jun 11 '15 at 17:57
  • What you understand is more or less correct, but you're missing a key point. GLSL only gives guaranteed behavior like that if you use the `std140` layout qualifier. Otherwise, the driver's free to re-arrange the structure any way it sees fit. If you're not going to query the offsets manually then you need to use a layout qualifier with guaranteed alignment rules (e.g. `std140` or `std430`). – Andon M. Coleman Jun 13 '15 at 20:14
  • @AndonM.Coleman interesting to know. Can you post that as the answer? – jozxyqk Jun 15 '15 at 04:10
  • @Andon M. Coleman: As I indicated in my edit, I use the std140 layout for all uniforms in the shaders. – MRenauld Jun 15 '15 at 12:04
  • @jozxyqk: Could you tell me which command to use to get the location of variables in named UBOs? I tried with glGetUniformLocation, but according to [this doc](https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniformLocation.xhtml) it does not work for named uniform blocks. – MRenauld Jun 15 '15 at 12:08
  • As per the answer in my link, it looks like [`glGetProgramResource`](https://www.opengl.org/wiki/GLAPI/glGetProgramResource) is the way to go. Look for `GL_OFFSET`. – jozxyqk Jun 15 '15 at 12:16
  • Solved? Try to pad the `lightAttenuation`, `float padding[3];` – elect Aug 07 '15 at 08:42
  • @elect I tried adding a padding after `lightAttenuation`, but it does not solve the problem. Currently I am still running the version with duplicate variables instead of an array. It is less optimal, but it is working. – MRenauld Aug 10 '15 at 05:58
  • Can you double check you call at the init: `glGenBuffers`, `glBindBuffer`, `glBufferData` to allocate passing null and size = 40 F = 160 B, `glBindBufferRange` passing a specific id. `glUniformBlockBinding` at the shader creation. Also `glGetUniformBlockIndex` must use `Light`. What is your `GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT`? Fill the buffer with the padding and double check printing it all out before submitting it with `glBufferSubData`. – elect Aug 10 '15 at 07:26
  • Check [this tutorial](https://bitbucket.org/alfonse/gltut/src/1d1479cc7027f1e32c5adff748f3b296f1931d84/Tut%2012%20Dynamic%20Range/Scene%20Lighting.cpp?at=default), if you don't know it already. – elect Aug 10 '15 at 07:28
  • @elect Yes I called all the operations you mention. In fact my code is a Java/JOGL translation of the tutorial you linked in the above comment. The value of `GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT` is 16. – MRenauld Aug 11 '15 at 06:22
  • Are you hosting your code somewhere where I can take a look? If no, add to the question all the calls I wrote, especially the size passed to `glBindBufferRange` and `glBufferSubData`. What is your `GL_UNIFORM_BLOCK_SIZE_DATA`? – elect Aug 11 '15 at 07:21
  • Moreover, use `GLBuffers.newDirectFloatBuffer` – elect Aug 11 '15 at 09:11

0 Answers0