GLSL shaders using normal as vertex positions

Alec Jacobson

November 14, 2015

weblog/

Every few months I need to relearn how properly set up a GLSL shader with a vertex array object. This time I was running into a strange bug where my normals were being used as vertex positions. I had a simple pass-through vertex shader looking something like:

#version 330 core
in vec3 position;
in vec3 normal;
out vec3 frag_normal;
void main()
{                                      
  gl_Position = position;
  frag_normal = normal;
}

And on the CPU side I was setting up my vertex attributes with:

glVertexAttribPointer(0,3, ... );
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,position_buffer_object);
glVertexAttribPointer(1,3, ... );
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,normal_buffer_object);

My folly was assuming that because I'd declared position and normal in that order in the vertex shader that they'd be bound to attribute ids 0 and 1 respectively. Not so! After some head-slamming I thought to query these ids using:

glGetAttribLocation(program_id,"position");
glGetAttribLocation(program_id,"normal");

And found that for whatever reason position was bound to 0 and normal was bound to 1. Of course I then tried hacks to get these to reverse order, or I could hard code the different order. But there appears to be two correct options for fixing this problem:

The obvious one is to use glGetAttribLocation when creating the vertex array object:

glVertexAttribPointer(glGetAttribLocation(program_id,"position"),3, ... );
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,position_buffer_object);
...

I was a little bothered that this solution requires that I know which shader is going to be in use at the time of creating the vertex array object.

The opposite solution is to assume a certain layout on the CPU-side when writing the shader:

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;

Now I can be sure that using ids 0 and 1 will correctly bind to position and normal respectively.