In my pursuit to write code that matches todays OpenGL standards I have found that I am completely clueless about interleaving arrays. I've tried and debugged just about everywhere I can think of but I can't get my model to render using interleaved arrays (It worked when it was configuered to use multiple arrays) Now I know that all the data is properly being parsed from an obj file and information is being copied properly copied into the Vertex object array, but I still can't seem to get anything to render. Below is the code for initializing a model and drawing it (along with the Vertex struct for reference.)


struct Vertex {
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 uv;
    glm::vec3 tangent;
    glm::vec3 bitangent;

Model Constructor:

Model::Model(const char* filename) {
    bool result = loadObj(filename, vertices, indices);

    glGenVertexArrays(1, &vertexArrayID);

    glGenBuffers(1, &vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

    glGenBuffers(1, &elementbuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);

Draw Model:

Model::Draw(ICamera camera) {
    GLuint matrixID = glGetUniformLocation(programID, "mvp");
    GLuint positionID = glGetAttribLocation(programID, "position_modelspace");
    GLuint uvID = glGetAttribLocation(programID, "uv");
    GLuint normalID = glGetAttribLocation(programID, "normal_modelspace");
    GLuint tangentID = glGetAttribLocation(programID, "tangent_modelspace");
    GLuint bitangentID = glGetAttribLocation(programID, "bitangent_modelspace");

    glm::mat4 projection = camera->GetProjectionMatrix(); 
    glm::mat4 view = camera->GetViewMatrix();
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 mvp = projection * view * model;

    glUniformMatrix4fv(matrixID, 1, GL_FALSE, &mvp[0][0]);


    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(positionID, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].position);

    glVertexAttribPointer(uvID, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].uv);

    glVertexAttribPointer(normalID, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].normal);

    glVertexAttribPointer(tangentID, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].tangent);

    glVertexAttribPointer(bitangentID, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].bitangent);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void*)0);

  • \$\begingroup\$ Why are you trying to interleave arrays? You shouldn't complicate your code unless you have a clear reason for it. I assume you're doing it for some potential speed improvements; you should only do things like this if you can benchmark that it actually speed things up.. In fact, in certain environments, interleaved arrays actually make things slower. \$\endgroup\$ Oct 12, 2012 at 17:17
  • 1
    \$\begingroup\$ @JariKomppa well I can't exactly bench mark this because it is not working to begin with. I realize this can be inefficient in some cases, but the goal is just to get it working for now and worry about optimization later. \$\endgroup\$ Oct 12, 2012 at 17:19
  • \$\begingroup\$ Did you have it working without interleaving first? \$\endgroup\$ Oct 12, 2012 at 17:21
  • \$\begingroup\$ Have you tried gDEBugger? It's fairly nice for debugging openGL issues. \$\endgroup\$
    – House
    Oct 12, 2012 at 17:21
  • \$\begingroup\$ @JariKomppa yep, I mentioned in the question that it was working fine with multiarrays (aside from a small lighting issue) but when I modified the code to what I think would work for interleaving, I'm coming up blank. The only modifications are to the code shown. \$\endgroup\$ Oct 12, 2012 at 17:23

1 Answer 1


I think you want to change your attribute pointers, specifically the offsets you have listed. &vertices[0].position should be 0, &vertices[0].normal should be 12, &vertices[0].uv should be 24, and so on.

Since getting the address of a struct member gives you the absolute address instead of the address relative to the beginning of the struct. glVertexAttribPointer is looking for the offset into your interleaved set.

struct Vertex {          //previousfloats * sizeof(float) = offset
    glm::vec3 position;  // 0 * 4 = 0
    glm::vec3 normal;    // 3 * 4 = 12
    glm::vec2 uv;        // 6 * 4 = 24
    glm::vec3 tangent;   // 8 * 4 = 32
    glm::vec3 bitangent; // 11 * 4 = 44

See the documentation for the glVertexAttribPointer here. The big hint being:


Specifies a pointer to the first component of the first generic vertex attribute in the array. The initial value is 0.

  • \$\begingroup\$ Ah, well done, I feel a little dumb about the error being something that small (although slightly proud for just guessing at what the code should be and coming that close.) My hat is off to you and your amazing debugging skills sir. \$\endgroup\$ Oct 12, 2012 at 17:44
  • \$\begingroup\$ No problem, did it actually solve the problem? Pretty nice if that was the single little thing that was wrong. \$\endgroup\$
    – House
    Oct 12, 2012 at 17:47
  • \$\begingroup\$ That was the exact issue. I replaced the actually (void*)int pointers with just offsetof(...) to make it a bit simpler to read, but that was my exact problem. Thanks again for your help. \$\endgroup\$ Oct 12, 2012 at 17:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .