Uniform Buffer Object and some issues with it

Hello forum,

I have implemented a uniform buffer object with simpler settings and now i am confused once i started to try with something complex. And i need some hint to get around this issue. Lets start with simpler setting that i have implemented with the shared layout.


uniform blobSettings
{
	vec4 innerColor;
	vec4 outerColor;
	float innerRadius;
	float outerRadius;
} blob;

The uniform block is defined inside the fragment shader. Then in the application side , i get the uniform block index with the following snippet:


    //get the index of the named uniform block
    GLuint blockIndex = glGetUniformBlockIndex(programHandle,"blobSettings");

Now I get the size of the uniform block buffer with the following snippet:


    //get the  space for the buffer
    GLint blockSize;
    glGetActiveUniformBlockiv(programHandle,blockIndex,GL_UNIFORM_BLOCK_DATA_SIZE,&blockSize);

Then allocate the buffer on the application side with the buffer size we have extracted :


    //allocate memory with the buffer size
    GLubyte *blockBuffer = NULL;
    blockBuffer = (GLubyte*) malloc(blockSize);

I need to query the offset of the each member of the uniform block as follows:


    //query the offsets of each block variable
    const GLchar *names[] = {"blobSettings.innerColor",
                             "blobSettings.outerColor",
                             "blobSettings.innerRadius",
                             "blobSettings.outerRadius"};

 We are using the shared layout, so we can determine the offsets
 that OpenGL assigned for the block members.
 Each member of the uniform block has an index that is used to
 refer to it to find its size and location within the block

    GLuint indices[4];
    //retrieve the indices of the uniform block members
    glGetUniformIndices(programHandle,4,names,indices);

now i have the indices, so next we can use
the indices to find the locations of the block
members within the buffer

    GLint offset[4];

    //the following function gives a lot of information
    //about specific uniform block members
    glGetActiveUniformsiv(programHandle,4,indices,GL_UNIFORM_OFFSET,offset);

Now I copied the data from the application to the uniform buffer object.


    //store the data within the buffer at appropriate offsets
    GLfloat outerColor[] = {0.0f,0.0f,0.0f,0.0f};
    GLfloat innerColor[] = {1.0f,0.0f,0.75f,1.0f};
    GLfloat innerRadius = 0.25f,outerRadius = 0.45f;

    //place the data into the buffer at appropriate offsets
    memcpy(blockBuffer + offset[0],innerColor,4 * sizeof(GLfloat));
    memcpy(blockBuffer + offset[1],outerColor,4 * sizeof(GLfloat));
    memcpy(blockBuffer + offset[2],&innerRadius,sizeof(GLfloat));
    memcpy(blockBuffer + offset[3],&outerRadius,sizeof(GLfloat));

    //create the buffer object and copy the data
    GLuint uboHandle;
    glGenBuffers(1,&uboHandle);
    glBindBuffer(GL_UNIFORM_BUFFER,uboHandle);
    glBufferData(GL_UNIFORM_BUFFER,blockSize,blockBuffer,GL_DYNAMIC_DRAW);

    glUniformBlockBinding(programHandle,blockIndex,0);

    //bind the buffer object to the uniform block
    //so that the data in the buffers appear in the uniform blocks
    glBindBufferBase(GL_UNIFORM_BUFFER,0,uboHandle);

The above uniform block was pretty simpler. Now i have some thing different data layout in the shared manner and i am having trouble to do the data transfer. The uniform block is as follows:


struct droplet_t
{
  float x_offset;
  float y_offset;
  float orientation;
  float unused;
};

uniform Droplets
{
  droplet_t droplet[256];
} droplets;

Then I followed the similar procedure to get the index,offset, stirde for the block member:


    //pull out necessary information to create the uniform buffer object
    //get the program handle
    GLuint programHandle = textureRainShader->GetProgramHandle();

    //get the index of the named uniform block
    GLuint blockIndex = glGetUniformBlockIndex(programHandle,"Droplets");

    //get the  space for the buffer
    GLint blockSize;
    glGetActiveUniformBlockiv(programHandle,blockIndex,GL_UNIFORM_BLOCK_DATA_SIZE,&blockSize);

    //allocate memory with the buffer size
    GLubyte *blockBuffer = NULL;
    blockBuffer = (GLubyte*) malloc(blockSize);

    //query the offsets of each block variable
    const GLchar *names[] = {"Droplets.droplet"};

    /*
     * We are using the shared layout, so we can determine the offsets
     * that OpenGL assigned for the block members.
     * Each member of the uniform block has an index that is used to
     * refer to it to find its size and location within the block
     */

    GLuint index;
    //retrieve the index of the uniform block member
    glGetUniformIndices(programHandle,1,names,&index);

    //now i have the index, so next we can use
    //the index to find the location of the uniform
    //block member within the buffer
    GLint offset,arrayStride;

    //the following function gives a lot of information
    //about specific uniform block members
    glGetActiveUniformsiv(programHandle,1,&index,GL_UNIFORM_OFFSET,&offset);
    glGetActiveUniformsiv(programHandle,1,&index,GL_UNIFORM_ARRAY_STRIDE,&arrayStride);

Now i am in dilemma on how to copy the data from the application buffer to the uniform buffer object . I initialized the data in the application side as follows:


float *dropletXOffset = NULL;
float *dropletRotSpeed = NULL;
float *dropletFallSpeed = NULL;
...............................
...............................

    dropletXOffset = new float[256];
    dropletRotSpeed = new float[256];
    dropletFallSpeed = new float[256];

.................................
.................................

    //initialize with the random data to populate
    //the buffer with it
    for(unsigned int i = 0; i < 256; i++)
    {
        dropletXOffset[i] = random_float() * 2.0 - 1.0f;
        dropletRotSpeed[i] = (random_float() + 0.5f) * ((i & 1) ? -3.0f : 3.0f);
        dropletFallSpeed[i] = random_float() + 0.2f;
    }

Now how to transfer the data to the blockBuffer ? Any hint folks ?

I guessed the following , but not sure about it.


         for(unsigned int i = 0; i < 256;i++)
         {
               *((float*) (blockBuffer + offset[0])) = dropletXOffset[i];
               *((float*) (blockBuffer + offset[1])) = 2.0f - fmodf((t + float(i)) * dropletFallSpeed[i], 4.31f);
               *((float*) (blockBuffer + offset[2]))  = t * dropletRotSpeed[i]; // t is the current time here
               *((float*) (blockBuffer + offset[3])) = 0.0;

               offset += arrayStride;
         }

Please check the last code block and make some suggestion for me. The type we are dealing with is basically droplet_t type. Is casting to float to one of its members are valid ?

Thanks
Sajjad

In cases like this you’re really better off just using std140. I know that doesn’t answer your question, but IMO unless you have a really good reason to not use std140 (and experimenting with and learning about other layouts might be such a reason) then you should be using it.