How to use glBufferSubData properly?

Hello,

Below is how it works now, but then it is hard to manage if data needs to be updated.
I would like to separate vertices, normals and text coordinates for efficiency.

[Current]

void DrawCube() {
    float vertices[] = {
        // back face
        -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
        1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 1.0f, 1.0f, // top-right
        1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 1.0f, 0.0f, // bottom-right         
        1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 1.0f, 1.0f, // top-right
        -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
        -1.0f,  1.0f, -1.0f,  0.0f,  0.0f, -1.0f, 0.0f, 1.0f, // top-left

        // front face
        -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f, 0.0f, // bottom-left
        1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f, 0.0f, // bottom-right
        1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f, 1.0f, // top-right
        1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f, 1.0f, // top-right
        -1.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f, 1.0f, // top-left
        -1.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f, 0.0f, // bottom-left

        // left face
        -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f, 1.0f, 0.0f, // top-right
        -1.0f,  1.0f, -1.0f, -1.0f,  0.0f,  0.0f, 1.0f, 1.0f, // top-left
        -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, 0.0f, 1.0f, // bottom-left
        -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, 0.0f, 1.0f, // bottom-left
        -1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  0.0f, 0.0f, 0.0f, // bottom-right
        -1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  0.0f, 1.0f, 0.0f, // top-right

        // right face
        1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 1.0f, 0.0f, // top-left
        1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 0.0f, 1.0f, // bottom-right
        1.0f,  1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 1.0f, 1.0f, // top-right         
        1.0f, -1.0f, -1.0f,  1.0f,  0.0f,  0.0f, 0.0f, 1.0f, // bottom-right
        1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 1.0f, 0.0f, // top-left
        1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  0.0f, 0.0f, 0.0f, // bottom-left     

        // bottom face
        -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f, 0.0f, 1.0f, // top-right
        1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f, 1.0f, 1.0f, // top-left
        1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f, 1.0f, 0.0f, // bottom-left
        1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f, 1.0f, 0.0f, // bottom-left
        -1.0f, -1.0f,  1.0f,  0.0f, -1.0f,  0.0f, 0.0f, 0.0f, // bottom-right
        -1.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f, 0.0f, 1.0f, // top-right

        // top face
        -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f, 0.0f, 1.0f, // top-left
        1.0f,  1.0f , 1.0f,  0.0f,  1.0f,  0.0f, 1.0f, 0.0f, // bottom-right
        1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f, 1.0f, 1.0f, // top-right     
        1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f, 1.0f, 0.0f, // bottom-right
        -1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f, 0.0f, 1.0f, // top-left
        -1.0f,  1.0f,  1.0f,  0.0f,  1.0f,  0.0f, 0.0f, 0.0f  // bottom-left        
    };

    // Return n vertex array object names in arrays
    glGenVertexArrays(1, &VAO);

    // Return n buffer object names in buffers
    glGenBuffers(1, &VBO);

    // Bind a named buffer object
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    // Create a new data store for a buffer object
    glBufferData(GL_ARRAY_BUFFER, object3D.vPointSize * POINT_ARRAY_SIZE * sizeof(float), vertice3D, GL_STATIC_DRAW);

    // Bind the VAO
    glBindVertexArray(cubeVAO);

    // Generic vertex attribute array specified by index
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);

    // Generic vertex attribute array specified by index
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));

    // Generic vertex attribute array specified by index
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));

    // Unbind buffer object
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // Unbind VAO
    glBindVertexArray(0);

    // Bind the VAO
    glBindVertexArray(VAO);

    // Draw cube
    glDrawArrays(GL_TRIANGLES, 0, 36);

    // Unbind VAO
    glBindVertexArray(0);
}

So far I’ve tried something like below but seems not working at all, anything I’m doing wrong here?

[Want to do]

void DrawCube() {
    float Vertices[] = {
        // back face
        -1.0f, -1.0f, -1.0f, // bottom-left
        1.0f,  1.0f, -1.0f,  // top-right
        1.0f, -1.0f, -1.0f,  // bottom-right         
        1.0f,  1.0f, -1.0f,  // top-right
        -1.0f, -1.0f, -1.0f, // bottom-left
        -1.0f,  1.0f, -1.0f, // top-left
    
        // front face
        -1.0f, -1.0f,  1.0f, // bottom-left
        1.0f, -1.0f,  1.0f,  // bottom-right
        1.0f,  1.0f,  1.0f,  // top-right
        1.0f,  1.0f,  1.0f,  // top-right
        -1.0f,  1.0f,  1.0f, // top-left
        -1.0f, -1.0f,  1.0f, // bottom-left
    
        // left face
        -1.0f,  1.0f,  1.0f, // top-right
        -1.0f,  1.0f, -1.0f, // top-left
        -1.0f, -1.0f, -1.0f, // bottom-left
        -1.0f, -1.0f, -1.0f, // bottom-left
        -1.0f, -1.0f,  1.0f, // bottom-right
        -1.0f,  1.0f,  1.0f, // top-right
    
        // right face
        1.0f,  1.0f,  1.0f,  // top-left
        1.0f, -1.0f, -1.0f,  // bottom-right
        1.0f,  1.0f, -1.0f,  // top-right         
        1.0f, -1.0f, -1.0f,  // bottom-right
        1.0f,  1.0f,  1.0f,  // top-left
        1.0f, -1.0f,  1.0f,  // bottom-left     
    
        // bottom face
        -1.0f, -1.0f, -1.0f, // top-right
        1.0f, -1.0f, -1.0f,  // top-left
        1.0f, -1.0f,  1.0f,  // bottom-left
        1.0f, -1.0f,  1.0f,  // bottom-left
        -1.0f, -1.0f,  1.0f, // bottom-right
        -1.0f, -1.0f, -1.0f, // top-right
    
        // top face
        -1.0f,  1.0f, -1.0f, // top-left
        1.0f,  1.0f , 1.0f,  // bottom-right
        1.0f,  1.0f, -1.0f,  // top-right     
        1.0f,  1.0f,  1.0f,  // bottom-right
        -1.0f,  1.0f, -1.0f, // top-left
        -1.0f,  1.0f,  1.0f  // bottom-left        
    };
    
    float Normals[] = {
        // back face
        0.0f,  0.0f, -1.0f,  // bottom-left
        0.0f,  0.0f, -1.0f,  // top-right
        0.0f,  0.0f, -1.0f,  // bottom-right         
        0.0f,  0.0f, -1.0f,  // top-right
        0.0f,  0.0f, -1.0f,  // bottom-left
        0.0f,  0.0f, -1.0f,  // top-left
    
    
        0.0f,  0.0f,  1.0f,  // bottom-left
        0.0f,  0.0f,  1.0f,  // bottom-right
        0.0f,  0.0f,  1.0f,  // top-right
        0.0f,  0.0f,  1.0f,  // top-right
        0.0f,  0.0f,  1.0f,  // top-left
        0.0f,  0.0f,  1.0f,  // bottom-left
    
    
        -1.0f,  0.0f,  0.0f, // top-right
        -1.0f,  0.0f,  0.0f, // top-left
        -1.0f,  0.0f,  0.0f, // bottom-left
        -1.0f,  0.0f,  0.0f, // bottom-left
        -1.0f,  0.0f,  0.0f, // bottom-right
        -1.0f,  0.0f,  0.0f, // top-right
    
    
        1.0f,  0.0f,  0.0f,  // top-left
        1.0f,  0.0f,  0.0f,  // bottom-right
        1.0f,  0.0f,  0.0f,  // top-right         
        1.0f,  0.0f,  0.0f,  // bottom-right
        1.0f,  0.0f,  0.0f,  // top-left
        1.0f,  0.0f,  0.0f,  // bottom-left     
    
    
        0.0f, -1.0f,  0.0f,  // top-right
        0.0f, -1.0f,  0.0f,  // top-left
        0.0f, -1.0f,  0.0f,  // bottom-left
        0.0f, -1.0f,  0.0f,  // bottom-left
        0.0f, -1.0f,  0.0f,  // bottom-right
        0.0f, -1.0f,  0.0f,  // top-right
    
    
        0.0f,  1.0f,  0.0f,  // top-left
        0.0f,  1.0f,  0.0f,  // bottom-right
        0.0f,  1.0f,  0.0f,  // top-right     
        0.0f,  1.0f,  0.0f,  // bottom-right
        0.0f,  1.0f,  0.0f,  // top-left
        0.0f,  1.0f,  0.0f   // bottom-left        
    };
    
    float TextCoords[] = {
        // back face
        0.0f, 0.0f, 		 // bottom-left
        1.0f, 1.0f, 		 // top-right
        1.0f, 0.0f, 		 // bottom-right         
        1.0f, 1.0f, 		 // top-right
        0.0f, 0.0f, 		 // bottom-left
        0.0f, 1.0f, 		 // top-left
    
    
        0.0f, 0.0f, 		 // bottom-left
        1.0f, 0.0f, 		 // bottom-right
        1.0f, 1.0f, 		 // top-right
        1.0f, 1.0f, 		 // top-right
        0.0f, 1.0f, 		 // top-left
        0.0f, 0.0f, 		 // bottom-left
    
    
        1.0f, 0.0f, 		 // top-right
        1.0f, 1.0f, 		 // top-left
        0.0f, 1.0f, 		 // bottom-left
        0.0f, 1.0f, 		 // bottom-left
        0.0f, 0.0f, 		 // bottom-right
        1.0f, 0.0f, 		 // top-right
    
    
        1.0f, 0.0f, 		 // top-left
        0.0f, 1.0f, 		 // bottom-right
        1.0f, 1.0f, 		 // top-right         
        0.0f, 1.0f, 		 // bottom-right
        1.0f, 0.0f, 		 // top-left
        0.0f, 0.0f, 		 // bottom-left     
    
    
        0.0f, 1.0f, 		 // top-right
        1.0f, 1.0f, 		 // top-left
        1.0f, 0.0f, 		 // bottom-left
        1.0f, 0.0f, 		 // bottom-left
        0.0f, 0.0f, 		 // bottom-right
        0.0f, 1.0f, 		 // top-right
    
    
        0.0f, 1.0f, 		 // top-left
        1.0f, 0.0f, 		 // bottom-right
        1.0f, 1.0f, 		 // top-right     
        1.0f, 0.0f, 		 // bottom-right
        0.0f, 1.0f, 		 // top-left
        0.0f, 0.0f  		 // bottom-left        
    };
    
    // Return n vertex array object names in arrays
    glGenVertexArrays(1, &VAO);

    // Return n buffer object names in buffers
    glGenBuffers(1, &VBO);

    // Bind a named buffer object
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    // Create a new data store for a buffer object
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices) * sizeof(float), Vertices, GL_STATIC_DRAW);
    
    // Bind the VAO
    glBindVertexArray(VAO);

    // Fill buffers
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertices), &Vertices);
    glBufferSubData(GL_ARRAY_BUFFER, sizeof(Vertices), sizeof(Normals), &Normals);
    glBufferSubData(GL_ARRAY_BUFFER, sizeof(Vertices) + sizeof(Normals), sizeof(TextCoords), &TextCoords);
    
    // Generic vertex attributes array specified by index
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(Vertices)));
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(Vertices) + sizeof(Normals)));

    // Unbind buffer object
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // Unbind VAO
    glBindVertexArray(0);

    // Bind the VAO
    glBindVertexArray(VAO);

    // Draw cube
    glDrawArrays(GL_TRIANGLES, 0, 36);

    // Unbind VAO
    glBindVertexArray(0);
}

Thanks!!!

Store each attribute array in a separate buffer, or in a separate contiguous region of a common buffer. Change the glVertexAttribPointer calls accordingly.

Using separate buffers allows you to specify different usage hints or to discard and re-create individual buffers.

Note that replacing the entire contents of the buffer with glBufferData (or glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT) may be faster than replacing specific portions, as it’s easier for the implementation to orphan the existing data store (disassociate it from the buffer object while retaining the data until pending commands have finished using it) if you eliminate the possibility of reading any previous contents.

For more information on efficiently updating buffers, see Buffer Object Streaming in the wiki.

Thanks, I think my question wasn’t clear enough.
I may need to create new article which I want to achieve, as it is somehow irrelevant with current title

Ok, so basically (I think) you want to convert:

  • FROM vertex attribute data that is stored pre-interleaved in hard-coded CPU arrays and uploaded to the GPU in a single buffer object as-is (VNTVNT…)
  • TO vertex attribute data that is non-interleaved in hard-coded CPU arrays and uploaded to sequential subregions of the same GPU buffer object on the GPU (VVV…NNN…TTT…)

?

There are quite a few errors here, but I won’t go off on those until you verify that’s this is generally what you’re trying to accomplish. You also don’t show all the relevant decls, which make it impossible to verify some things.