OpenGL - Explicit uniform location at different stages of shaders

How to assign an explicit uniform location when I want to use the form at different stages of the shader of the same program?

When using automatic assignment, uniforms at different stages are assigned to the same place when the identifiers match. But how can I determine the location in the shader using

layout (location = ...) 

syntax?

The following quote from: https://www.opengl.org/wiki/Uniform_(GLSL)/Explicit_Uniform_Location

You cannot assign the same uniform arrangement to two forms in the same shader or the same program. Even if these two forms have the same name and type and are defined at different stages of the shader, it is impractical to explicitly assign them the same uniform location; linker error.

The following quote from the GLSL specification:

There are no two identical default variables in the program that can have the same location, even if they are not used, otherwise a compile time or bind time error will be generated.

I am using OpenGL 4.3.

Due to the huge CODE READING, I realized that the uniform is not used. This leads to the following situation: on the GTX 780, the following code works without problems (although it seems that it should not). The code on the Intel HD 5500 integrated graphics chip generates a SHADER_ID_LINK error during a connection in accordance with the GL_ARB_DEBUG_OUTPUT extension. It states that a uniform location overlaps another uniform.

Vertex Shader:

 #version 430 core layout(location = 0) in vec4 vPosition; layout(location = 2) in vec4 vTexCoord; layout(location = 0) uniform mat4 WorldMatrix; // <-- unused in both stages out vec4 fPosition; out vec4 fTexCoord; void main() { ... } 

Fragment Shader:

 #version 430 core in vec4 fPosition; in vec4 fTexCoord; layout(location = 0) out vec4 Albedo; layout(location = 1) out vec4 Normal; layout(location = 0) uniform mat4 WorldMatrix; // <-- unused in both stages layout(location = 1) uniform mat4 InverseViewProjectionMatrix; layout(location = 2) uniform samplerCube Cubemap; void main() { ... } 

However, when uniforms are used, no problems arise. Suppose I interpret the GLSL Spec right, this does not seem to be as intended. Although, that’s how I would like it to work.

However, there is a problem of overlapping uniforms when the uniform is not in use.

+5
source share
1 answer

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; 
  • you need to specify the GLSL version to use this
  • not sure if they add layout layout, but for 400+ it will work confidently

  • VBO pos set to position 0

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.
+1
source

All Articles