1
\$\begingroup\$

I've been getting some strange results when trying to implement a normals buffer for the purpose of rendering lighting. It seems to be related to the indexes for glEnableVertexAttribArray, glVertexAttribPointer and the location value in the vertex shader. Take a look at the following code for example:

  gl.glEnableVertexAttribArray(1);
  gl.glEnableVertexAttribArray(0);

  //bind vertex data - why does the index have to be 1?
  gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboHandles[VERTICES_IDX]); //the vertex data
  gl.glVertexAttribPointer(1,3,GL4.GL_FLOAT, false,  0,0);


  // Select the VBO, GPU memory data, to use for colors
  // - why doe the index have to be 0??
  gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboHandles[COLOR_IDX]);
  gl.glVertexAttribPointer(0, 3, GL4.GL_FLOAT, false, 0, 0);      

  //bind IBO
  gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, vboHandles[2]);

Where do the values for the indexes used in the above functions come from? If I were to switch them and make the color buffer 1 and the vertex buffer 0, nothing renders. It seems logical to me that the vertices should be applied first and then the colors? My confusion is compounded when I try to pass the data to a shader. I thought the location value in the shader program referred to the index in glVertexAttribPointer but that doesn't seem to be the case. In fact it looks like location is being completely ignored (targeting GLSL 430). Have a look at this:

From the shader:

layout (location=0) in vec3 vertexPosition;
layout (location=1) in vec3 vertexNormal;

The Java code:

//with glEnableVertexAttribArray 0 and 1 enabled all of the cubes render but they 
//are individually lighted - ie the shading doesn't propagate over the whole scene,
//only over each cube.
//if i rem 1, the scene looks lighted properly.  So only 1 vertex array enabled
//and it still works?
  gl.glEnableVertexAttribArray(0);
  gl.glEnableVertexAttribArray(1);
  //gl.glEnableVertexAttribArray(2);


  gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboHandles[VERTICES_IDX]); 
  //with the index set to 5 (doesn't relate to any other index) the scene still 
  //renders... 
  gl.glVertexAttribPointer(5,3,GL4.GL_FLOAT, false,  0,0);

  //normals
  gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboHandles[3]);
  gl.glVertexAttribPointer(1, 3, GL4.GL_FLOAT, false, 0, 0);    

      // Select the VBO, GPU memory data, to use for colors
  //almost strangest of all.  If I remove colors the program crashes.  I don't 
  //even use this buffer..
  gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboHandles[COLOR_IDX]);
  gl.glVertexAttribPointer(0, 3, GL4.GL_FLOAT, false, 0, 0);      

  //bind IBO
  gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, vboHandles[2]);

There is obviously something fundamental here that I am not understanding. I would think that by setting the glVertexAttribPointer index for the vertices to 5 it would unlink from the shader in variable as its location is 0. I need to know what is going on here especially now that I am implementing lighting. So, what is the relationship between the glVertexAttribPointer index and the shader location value? Also, why does the index have to be certain value (eg 0 for color, 1 for vertex)?

\$\endgroup\$
2
\$\begingroup\$

You can explicitly get those numbers from id = glGetAttribLocation(program, name); after linking; the name is the string that appears in the vertex shader for the attribute. For example if you passed "vertexPosition" for name then you would get 0.

If the layout information is not in the shader then openGL will create a default layout (usually in order as they appear) or you can define your own binding with glBindAttribLocation(progam, id, name) before linking.

\$\endgroup\$
  • \$\begingroup\$ So I can safely assume that glGetAttributeLocation will return 0 if I search for name 'vertexPosition' (my second example). So, shouldn't I have to then pass 0 to glVertexAttribPointer(index,.. after I call glBindBuffer for the vertex array? Currently it doesn't seem to matter what I pass in. I passed in a 5 and it still worked... \$\endgroup\$ – eric_the_animal Oct 19 '14 at 22:27
  • \$\begingroup\$ @eric_user1775643 depends on when you called glBindAttribLocation, if you call it after glLinkProgram then it won't have any effect; the locations are finalized during linking. \$\endgroup\$ – ratchet freak Oct 19 '14 at 23:03
  • \$\begingroup\$ Well it turns out that my problem was actually that I my indexes were switched calling glBindBuffer before glBufferData and glBindBuffer before glVertexAttribPointer. This is why what I thought should be 0 was 1.. I couldn't have found this out without the clear and simple answer provided by 'ratchet' to help me understand how those attribute indexes work. \$\endgroup\$ – eric_the_animal Oct 20 '14 at 3:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.