OpenGL ES: #define BUFFER_OFFSET(i) ((char *)NULL + (i)) explanation

Discussion in 'iOS Programming' started by Blakeasd, Jul 4, 2013.

  1. Blakeasd macrumors 6502a

    Joined:
    Dec 29, 2009
    #1
    Hello,

    Can someone better explain this macro used in many OpenGL ES programs:

    Code:
    #define BUFFER_OFFSET(i) ((char *)NULL + (i)) 
    I know why the macro is here, but I don't understand how it works, despite reading a couple of explanations across StackOverflow. I'd like to know how it works specifically in relation to
    Code:
    glVertexAttribPointer
    .

    The last needed parameter of
    Code:
    glVertexAttribPointer
    is a pointer to the first piece of vertex data.
    So why cast the result of the macro as a pointer to a char, when the data in the vertex array is a float? Is it due to the value of a char == 1 byte?

    I'm completely confused about how this works, could someone please provide some insight.

    Thanks!
     
  2. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #2
    The last parameter to glVertexAttribPointer isn't exactly a pointer to the first piece of vertex data. It's kinda nasty what it is. It's typed as a pointer, but it's really an offset value, in bytes, from the beginning of the vertex buffer. If you pass in a zero (NULL) it indicates that the first attribute you're talking about is at the beginning of the data store.

    The macro you show is nasty, but basically converts an integer value to pointer value that's the correct size for the target machine.
     
  3. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #3
    Thanks, but I'm still not sure how it works. Take the vertex data from Apple's default OpenGL ES template for example:

    Code:
    GLfloat gCubeVertexData[216] = 
    {
        // Data layout for each line below is:
        // positionX, positionY, positionZ,     normalX, normalY, normalZ,
        0.5f, -0.5f, -0.5f,        1.0f, 0.0f, 0.0f,
        0.5f, 0.5f, -0.5f,         1.0f, 0.0f, 0.0f,
        0.5f, -0.5f, 0.5f,         1.0f, 0.0f, 0.0f,
        0.5f, -0.5f, 0.5f,         1.0f, 0.0f, 0.0f,
        0.5f, 0.5f, -0.5f,          1.0f, 0.0f, 0.0f,
        0.5f, 0.5f, 0.5f,         1.0f, 0.0f, 0.0f,
        
        0.5f, 0.5f, -0.5f,         0.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, -0.5f,        0.0f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.5f,          0.0f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.5f,          0.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, -0.5f,        0.0f, 1.0f, 0.0f,
        -0.5f, 0.5f, 0.5f,         0.0f, 1.0f, 0.0f,
        
        -0.5f, 0.5f, -0.5f,        -1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,       -1.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.5f,         -1.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.5f,         -1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,       -1.0f, 0.0f, 0.0f,
        -0.5f, -0.5f, 0.5f,        -1.0f, 0.0f, 0.0f,
        
        -0.5f, -0.5f, -0.5f,       0.0f, -1.0f, 0.0f,
        0.5f, -0.5f, -0.5f,        0.0f, -1.0f, 0.0f,
        -0.5f, -0.5f, 0.5f,        0.0f, -1.0f, 0.0f,
        -0.5f, -0.5f, 0.5f,        0.0f, -1.0f, 0.0f,
        0.5f, -0.5f, -0.5f,        0.0f, -1.0f, 0.0f,
        0.5f, -0.5f, 0.5f,         0.0f, -1.0f, 0.0f,
        
        0.5f, 0.5f, 0.5f,          0.0f, 0.0f, 1.0f,
        -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
        0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
        0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
        -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f,        0.0f, 0.0f, 1.0f,
        
        0.5f, -0.5f, -0.5f,        0.0f, 0.0f, -1.0f,
        -0.5f, -0.5f, -0.5f,       0.0f, 0.0f, -1.0f,
        0.5f, 0.5f, -0.5f,         0.0f, 0.0f, -1.0f,
        0.5f, 0.5f, -0.5f,         0.0f, 0.0f, -1.0f,
        -0.5f, -0.5f, -0.5f,       0.0f, 0.0f, -1.0f,
        -0.5f, 0.5f, -0.5f,        0.0f, 0.0f, -1.0f
    };
    
    
    To get the vertex position they use BUFFER_OFFSET(0), which makes sense.

    Code:
        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
    
    Why does Apple use BUFFER_OFFSET(12) to get the normals though?

    Code:
        glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
    
    As a side note, why would 24 be the stride?

    I'm just not sure how to figure out what numbers to use in the BUFFER_OFFSET macro.

    Thanks!
     
  4. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #4
    On iOS, floats are 4 bytes. The vertex data has 3 floats for a position, followed by 3 floats for a normal. That's 6 floats total, then another pair of position x/y/z and normal x/y/x values.

    The "Stride" is the number of bytes to skip between repeats of the same thing.

    Since a position/normal pair is 6 floats, and each float is 4 bytes, a whole position+normal entry is 6*4=24 bytes. So to get to each subsequent position/normal pair, you skip ahead 24 bytes.

    In your code below the last parameter, a "pointer" (offset) to the location of the first position value is 0, since the very first thing in the vertex data (at offset 0) is a position value.

    The "pointer" (offset) to the location of the first normal value is 12, since you have to skip 3 floats (3x4 bytes = 12 bytes) to get past the position data to the normal data.



     
  5. Blakeasd thread starter macrumors 6502a

    Joined:
    Dec 29, 2009
    #5
    Thanks! I've finally gotten my first 'by myself' OpenGL ES programming working thank to your help!! :)
     

Share This Page