0

I have an OpenGL application with shaders that can render objects with texture.

When i create simple rectangle with 'interleaved' attributes like this:

GLuint createRectInterleaved(float fW, float fH) {
    GLuint vao;
    GLuint rect_buffer;

    float vertex_data[] = {
        // position       normal     texture coords
        -fW/2, -fH/2, 0,  0, 0, 1,   0, 0,  
         fW/2, -fH/2, 0,  0, 0, 1,   1, 0,
         fW/2,  fH/2, 0,  0, 0, 1,   1, 1,
        -fW/2, -fH/2, 0,  0, 0, 1,   0, 0,
         fW/2,  fH/2, 0,  0, 0, 1,   1, 1,
        -fW/2,  fH/2, 0,  0, 0, 1,   0, 1};


    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &rect_buffer);
    glBindBuffer(GL_ARRAY_BUFFER, rect_buffer);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertex_data),
                 vertex_data,
                 GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (3*sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*) (6*sizeof(float)));
    glEnableVertexAttribArray(2);


    return vao;
}

then the application works and the square is rendered with its texture as expected.

But if i use a sequential arrangement of the vertex attributes:

GLuint createRectSequential(float fW, float fH) {
    GLuint vao;
    GLuint rect_buffers[3];

    float vertex_positions[18] = {
        -fW/2, -fH/2, 0,
         fW/2, -fH/2, 0,
         fW/2,  fH/2, 0,
        -fW/2, -fH/2, 0,
         fW/2,  fH/2, 0,
        -fW/2,  fH/2, 0};

    float vertex_normals[18] = {
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1};

    float vertex_tc[12] = {
        0, 0,
        1, 0,
        1, 1,
        0, 0, 
        1, 1, 
        0, 1};


    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(3, rect_buffers);
    glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[0]);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertex_positions),
                 vertex_positions,
                 GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[1]);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertex_normals),
                 vertex_normals,
                 GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[2]);
    glBufferData(GL_ARRAY_BUFFER,
                 sizeof(vertex_tc),
                 vertex_tc,
                 GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
    glEnableVertexAttribArray(2);

    return vao;
}

then my application crashes in the call to

  glDrawArrays(GL_TRIANGLES, 0, 6);

Both VAOs are handled exactly the same - the only difference is the argument for glBindVertexArray() before drawing: either the interleaved or the sequential VAO.

If i comment out the creation of the texture attribute, the sequential VAO does not cause a crash.

What am i doing wrong in the 'sequential' version?

(edit: spelling mistake)

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
user1479670
  • 1,145
  • 3
  • 10
  • 22

1 Answers1

2

The glVertexAttribPointer are wrong in the second code sample. All of them operate on attribute 0. In the first version, they initialize all attributes from 0 to 2. Since you still enable those attributes but do not bind data to it, OpenGL tries to read from some memory that doesn't belong to the application.

The correct version would be:

glGenBuffers(3, rect_buffers);
glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[0]);
glBufferData(GL_ARRAY_BUFFER,
             sizeof(vertex_positions),
             vertex_positions,
             GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[1]);
glBufferData(GL_ARRAY_BUFFER,
             sizeof(vertex_normals),
             vertex_normals,
             GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
//                   /\ Corrected Attribute here
glEnableVertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER, rect_buffers[2]);
glBufferData(GL_ARRAY_BUFFER,
             sizeof(vertex_tc),
             vertex_tc,
             GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);
//                   /\ Corrected Attribute here
glEnableVertexAttribArray(2);
BDL
  • 21,052
  • 22
  • 49
  • 55