OpenGL - 不同着色器阶段的显式统一位置

时间:2015-09-05 19:25:09

标签: opengl graphics glsl shader

如果我想在同一程序的不同着色器阶段中使用制服,如何指定显式统一位置

使用自动分配时,不同阶段的制服在标识符匹配时分配到同一位置。但是如何使用

在着色器中定义位置
layout (location = ...)

语法?

以下引用: https://www.opengl.org/wiki/Uniform_(GLSL)/Explicit_Uniform_Location

  

将相同的统一位置分配给同一着色器或同一程序中的两个制服是违法的。即使这两个制服具有相同的名称和类型,并且在不同的着色器阶段中定义,但明确地为它们分配相同的统一位置是不合法的。将发生链接器错误。

以下引用GLSL规范:

  

程序中没有两个默认块统一变量可以具有相同的位置,   即使它们未被使用,否则将产生编译时或链接时错误。

我正在使用OpenGL 4.3。

由于阅读了很多代码,我发现,制服没用了。 这导致以下情况:在 GTX 780 上,以下代码运行没有问题(虽然它似乎不应该)。在 Intel HD 5500 板载图形芯片上,根据 GL_ARB_DEBUG_OUTPUT 扩展,代码在链接时产生 SHADER_ID_LINK 错误。它指出,统一的位置与另一个制服重叠。

顶点着色器:

#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() { ... }

但是,使用制服时,不会出现问题。假设我正确地解释了GLSL Spec,这似乎并不像它所假设的那样。虽然,这正是我希望它发挥作用的方式。

当没有使用制服时,仍存在重叠制服的问题。

1 个答案:

答案 0 :(得分:2)

请参阅complete GL+VAO/VBO+GLSL+shaders example in C++

  • 从该示例中提取:

在GPU方面:

#version 400 core
layout(location = 0) in vec3 pos;
  • 您需要指定GLSL版本才能使用此
  • 不确定从哪个位置添加布局位置,但对于400+,它肯定会起作用

  • VBO pos设置为位置0

在CPU端:

// globals
GLuint vbo[4]={-1,-1,-1,-1};
GLuint vao[4]={-1,-1,-1,-1};
const GLfloat vao_pos[]=
    {
//  x    y    z     //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);
data附加到location

然后你需要在单个阶段内使用它的所有着色器中为它设置layout location。您不能同时将同一位置分配给多个 VBO (这是您复制的所有状态)。

单个阶段是指单个/一组glDrawArrays/glDrawElements个调用而不更改着色器设置。如果您有更多着色器程序阶段(多个片段/顶点/几何体......),则可以为每个阶段设置不同的位置,但在每个阶段内,其所有着色器程序必须具有相同的位置设置。

通过单阶段开始,您可以假设每次glUseProgram(prog_id);来电,并以glUseProgram(0);或其他阶段开始结束......

[edit2]以下是非nVidia驱动程序的制服

顶点着色器:

// 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
#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);
    }

这些是来自链接示例的重写着色器,其中布局位置用于制服。你必须添加:

  • #extension GL_ARB_explicit_uniform_location : enable

用于400个人资料以使其有效

在CPU端像往常一样使用glGetUniformLocation

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);

或定义的位置:

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);

看起来 nVidia 编译器以不同方式处理位置。如果它无法正常运行,请尝试解决有缺陷的驱动程序的解决方法,以设置每种数据类型具有不同步骤的位置:

  • 1个地点:float,int,bool
  • 2个地点double
  • 3个地点vec3
  • 4个地点vec4
  • 6个地点dvec3
  • 8个地点dvec4
  • 9个地点mat3
  • 16个地点mat4
  • 等...