see the full example of GL + VAO / VBO + GLSL + shaders in C ++
- extracted from this example:
On the GPU side:
#version 400 core layout(location = 0) in vec3 pos;
On the processor side:
// globals GLuint vbo[4]={-1,-1,-1,-1}; GLuint vao[4]={-1,-1,-1,-1}; const GLfloat vao_pos[]= { // xyz //ix -1.0,-1.0,-1.0, //0 +1.0,-1.0,-1.0, //1 +1.0,+1.0,-1.0, //2 -1.0,+1.0,-1.0, //3 -1.0,-1.0,+1.0, //4 +1.0,-1.0,+1.0, //5 +1.0,+1.0,+1.0, //6 -1.0,+1.0,+1.0, //7 }; // init GLuint i; glGenVertexArrays(4,vao); glGenBuffers(4,vbo); glBindVertexArray(vao[0]); i=0; // VBO location glBindBuffer(GL_ARRAY_BUFFER,vbo[i]); glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW); glEnableVertexAttribArray(i); glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
when you attach data to location
then you need to set the layout location for it the same in all the shaders that it uses inside one stage. You cannot assign the same location to multiple VBOs at once (this is the state in which you copied everything).
One step means a single / set of calls to glDrawArrays/glDrawElements without changing the shader setting. If you have more stages of a shader program (more than one fragment / vertex / geometry ...), then the location can be set differently for each stage, but inside each stage all its shader programs must have the same location setting.
Through a one-step run, you can accept every call to glUseProgram(prog_id); , and it ends with glUseProgram(0); or another launch phase ...
[edit2] here is the form for nVidia drivers
vertex shader:
// Vertex #version 400 core #extension GL_ARB_explicit_uniform_location : enable layout(location = 0) in vec3 pos; layout(location = 2) in vec3 nor; layout(location = 3) in vec3 col; layout(location = 0) uniform mat4 m_model; // model matrix layout(location =16) uniform mat4 m_normal; // model matrix with origin=(0,0,0) layout(location =32) uniform mat4 m_view; // inverse of camera matrix layout(location =48) uniform mat4 m_proj; // projection matrix out vec3 pixel_pos; // fragment position [GCS] out vec3 pixel_col; // fragment surface color out vec3 pixel_nor; // fragment surface normal [GCS] void main() { pixel_col=col; pixel_pos=(m_model*vec4(pos,1)).xyz; pixel_nor=(m_normal*vec4(nor,1)).xyz; gl_Position=m_proj*m_view*m_model*vec4(pos,1); }
fragment shader:
// Fragment #version 400 core #extension GL_ARB_explicit_uniform_location : enable layout(location =64) uniform vec3 lt_pnt_pos;// point light source position [GCS] layout(location =67) uniform vec3 lt_pnt_col;// point light source color&strength layout(location =70) uniform vec3 lt_amb_col;// ambient light source color&strength in vec3 pixel_pos; // fragment position [GCS] in vec3 pixel_col; // fragment surface color in vec3 pixel_nor; // fragment surface normal [GCS] out vec4 col; void main() { float li; vec3 c,lt_dir; lt_dir=normalize(lt_pnt_pos-pixel_pos); // vector from fragment to point light source in [GCS] li=dot(pixel_nor,lt_dir); if (li<0.0) li=0.0; c=pixel_col*(lt_amb_col+(lt_pnt_col*li)); col=vec4(c,1.0); }
These are the rewritten shaders from a related example with the layout layout used for uniforms. You must add:
#extension GL_ARB_explicit_uniform_location : enable
for profile 400 to make it work
On the processor side, use glGetUniformLocation as usual
id=glGetUniformLocation(prog_id,"lt_pnt_pos"); glUniform3fv(id,1,lt_pnt_pos); id=glGetUniformLocation(prog_id,"lt_pnt_col"); glUniform3fv(id,1,lt_pnt_col); id=glGetUniformLocation(prog_id,"lt_amb_col"); glUniform3fv(id,1,lt_amb_col); glGetFloatv(GL_MODELVIEW_MATRIX,m); id=glGetUniformLocation(prog_id,"m_model" ); glUniformMatrix4fv(id,1,GL_FALSE,m); m[12]=0.0; m[13]=0.0; m[14]=0.0; id=glGetUniformLocation(prog_id,"m_normal" ); glUniformMatrix4fv(id,1,GL_FALSE,m); for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0; id=glGetUniformLocation(prog_id,"m_view" ); glUniformMatrix4fv(id,1,GL_FALSE,m); glGetFloatv(GL_PROJECTION_MATRIX,m); id=glGetUniformLocation(prog_id,"m_proj" ); glUniformMatrix4fv(id,1,GL_FALSE,m);
Or set position:
id=64; glUniform3fv(id,1,lt_pnt_pos); id=67; glUniform3fv(id,1,lt_pnt_col); id=70; glUniform3fv(id,1,lt_amb_col); glGetFloatv(GL_MODELVIEW_MATRIX,m); id= 0; glUniformMatrix4fv(id,1,GL_FALSE,m); m[12]=0.0; m[13]=0.0; m[14]=0.0; id=16; glUniformMatrix4fv(id,1,GL_FALSE,m); for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0; id=32; glUniformMatrix4fv(id,1,GL_FALSE,m); glGetFloatv(GL_PROJECTION_MATRIX,m); id=48; glUniformMatrix4fv(id,1,GL_FALSE,m);
It seems that the nVidia compiler handles locations differently. If it does not work properly, try a workaround for buggy drivers to set locations with different steps for each data type:
- 1 location:
float,int,bool - 2
double locations - 3
vec3 locations - 4
vec4 locations - 6
dvec3 locations - 8
dvec4 locations - 9
mat3 locations - 16
mat4 locations - etc.