Question

I have a Vertex data type which includes position (3), texture (2), and vertex normal (3). I'm passing these to a vertex shader using glVertexAttribPointer (see here).

Unfortunately, no matter what model I loaded in, it gave me the Death Star — basically a sphere of vertices which is only visible when I switch to wireframe rendering.

I tried deleting a bunch of vertices from my module, and eventually arrived at a partially constructed Death Star. At this point it became clear that it was plotting normals as if they were vertices. I don't know that the vertices are being plotted at all.

I confirmed my hypothesis by drawing two additional triangles — one to represent where vertices should be and the other to represent the normals. I also scaled them by 1.1 so they would be distinguishable from the object itself. And yes, it's definitely drawing normals instead of vertices.

Does anyone have any idea why? I've tried switching the order of the attributes in the shaders, but that didn't help (oddly).

Here's the complete minimum working example along with the two test objects (complete, n20r4_d5.obj; and very partial, test11.obj).

Was it helpful?

Solution

You're using OpenGL 2.1 so you have to pull the attribute indexes using glGetAttribLocation(). You can't just hope the GLSL compiler puts vertexes on 0 and texcoords on 2:

void render(Shader* shader_program = NULL) 
{
    if (shader_program) 
        shader_program->bind();

    GLint position_loc = glGetAttribLocation( shader_program->id(), "position" );
    GLint tex_loc = glGetAttribLocation( shader_program->id(), "tex" );
    GLint normal_loc = glGetAttribLocation( shader_program->id(), "normal" );

    glEnableVertexAttribArray( position_loc );
    glEnableVertexAttribArray( normal_loc );
    glEnableVertexAttribArray( tex_loc );

    for (size_t i = 0; i < entries.size(); ++i) 
    {
        glBindBuffer(GL_ARRAY_BUFFER, entries[i].vb);

        // I think this tells it where to look for the vertex information we've loaded.
        glVertexAttribPointer(position_loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
        glVertexAttribPointer(normal_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)12); // starts at 12 because 3 floats for position before 2 floats for normal
        glVertexAttribPointer(tex_loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)20); // makes room for 5 floats
        ...

You could also tell OpenGL where to put them (glBindAttribLocation()) before you link your shader but the way you have things set up would make that kinda messy.

In OpenGL 3.1+ you can force the compiler to put attributes on particular indexes via the layout qualifier.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top