1
$\begingroup$

I'm trying to load an array of float to a fragment shader using a uniform buffer object, but it doesn't work. In the fragment shader I declared the following uniform block:

/// Spectrum samples.
const int samples = 31;

layout(std140) uniform SpectralDataBlock {

    float illuminant[samples];
    float object[samples];
};

Then on client side in my C++ code:

float illuminant[31] = {
    82.754900,91.486000,93.431800,86.682300,104.865000,117.008000,117.812000,114.861000,115.923000,108.811000,109.354000,
    107.802000,104.790000,107.689000,104.405000,104.046000,100.000000,96.334200,95.788000,88.685600,90.006200,89.599100,
    87.698700,83.288600,83.699200,80.026800,80.214600,82.277800,78.284200,69.721300,71.609100
};

float object[31] = {
    0.051, 0.05, 0.049, 0.049, 0.049, 0.049, 0.048, 0.047, 0.045, 0.044,
    0.044, 0.044, 0.044, 0.044, 0.045, 0.047, 0.05, 0.057, 0.072, 0.109,
    0.192, 0.332, 0.486, 0.598, 0.654, 0.686, 0.7, 0.707, 0.718, 0.724,
    0.729
};

std::copy(illuminant, illuminant + 31, spectralData);
std::copy(object, object + 31, spectralData + 31);

blockId = glGetUniformBlockIndex(program, "SpectralDataBlock");
glUniformBlockBinding(program, blockId, bindingPoint);
glGetActiveUniformBlockiv(program, blockId, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);

glGenBuffers(1, &bufferId);
glBindBuffer(GL_UNIFORM_BUFFER, bufferId);
glBufferData(GL_UNIFORM_BUFFER, blockSize, spectralData, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, bufferId);

Unfortunately, the data doesn't get correctly loaded.

Are there any limitation in OpenGL ES the prevent to use float[] in an uniform buffer object? Are there any error in my code above?

$\endgroup$
2
  • 1
    $\begingroup$ Could you let us know what you mean by "doesn't get correctly loaded"? What specifically goes wrong that indicates this? $\endgroup$ Commented Jan 2, 2017 at 23:30
  • $\begingroup$ Hi @trichoplax, the problem is that the array doesn't contain any data. I'm sure of this because the data I'm trying to load is used to calculate the colours of objects using tristimulus values, but the object is always black. In fact, if I tested now that if I try to pass an array of 4 values and the block in the shader contains for example a single variable of type vec4, the code above works. Thanks. $\endgroup$ Commented Jan 2, 2017 at 23:33

1 Answer 1

5
$\begingroup$

Let's review what the specification says about std140 layout of arrays:

If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, according to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The array may have padding at the end; the base offset of the member following the array is rounded up to the next multiple of the base alignment.

Emphasis added.

So, if you have an array of float, the array stride shall be the same as the base alignment of a vec4. Also, each array will be padded at the end to the base alignment of a vec4. Yes, a float[] takes up the same room as a vec4[] of the same size.

Welcome to the wonderful world of std140 layout.

If you want to have a real array of floats in a UBO... well, it's best to avoid wanting that. But if you have absolutely no other choice, then I suggest making it an array of vec4. Obviously, the size of this array will be the size you actually want, divided by 4 and rounded up:

const int samples = 31;
const int arraySize = ((samples + 3) / 4);

To fetch a single float from this array, use math:

arrayOfVec4[index / 4][index % 4]

Note that OpenGL ES 3.0 does allow non-constant array indexing of vec and mat types. It also allows the integer operations needed to pull this off.

$\endgroup$
2
  • $\begingroup$ Thank you @Nicol_Bolas. Now it's clear (and I will use a standard uniform to pass my data to the shader). I will delete my other post on stack overflow, but can you remove the down vote, please? Thank you again. $\endgroup$ Commented Jan 2, 2017 at 23:58
  • 1
    $\begingroup$ @FabrizioDuroni a number of people have viewed this post. We don't know who the downvoter was. $\endgroup$ Commented Jan 3, 2017 at 0:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.