【问题标题】:OpenGL - Explicit Uniform Location in different Shader StagesOpenGL - 不同着色器阶段中的显式统一位置
【发布时间】:2015-09-05 19:25:08
【问题描述】:

当我想在同一程序的不同着色器阶段中使用统一时,如何分配显式统一位置

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

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

语法?

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

在同一着色器或同一程序中将相同的 Uniform 位置分配给两个 Uniform 是非法的。即使这两个uniform具有相同的名称和类型,并且定义在不同的着色器阶段,显式分配它们相同的uniform位置也是不合法的;将发生链接器错误。

以下引用 GLSL 规范:

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

我使用的是 OpenGL 4.3。

由于大量阅读代码,我发现制服未被使用。 这会导致以下情况:在 GTX 780 上,以下代码可以正常运行(尽管看起来不应该)。根据 GL_ARB_DEBUG_OUTPUT 扩展,在 Intel HD 5500 板载图形芯片上,代码会在链接时产生 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() { ... }

片段着色器:

#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 规范的解释是正确的,这似乎与预期的不同。不过,这正是我希望它发挥作用的方式。

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

【问题讨论】:

  • 你使用的是什么 OpenGL 版本?
  • OpenGL 版本为 4.3
  • 在阅读了原始扩展规范和最新的 GL 和 GLSL 规范之后,我仍然不确定预期的行为是什么。我发现禁止任何事情的唯一地方是“程序中没有两个默认块统一变量可以具有相同的位置,即使它们未使用,否则将生成编译时或链接时错误”引用你已经发现。但是在不同阶段使用相同的制服并不是在我的书中使用两个制服。但这可能只是我的解释。
  • 这种解释听起来很合理。我认为在正常情况下(没有未使用的制服)一切正常。但是当不使用制服时,这种行为具有高度的误导性。

标签: opengl graphics glsl shader


【解决方案1】:

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
  • 等等...

【讨论】:

  • 遗憾的是,这仅描述了有关属性的情况,而不是制服。该示例甚至没有使用统一的位置。
  • 感谢您的努力,但是这个例子在不同阶段没有使用相同的制服。这没有回答我的问题。
  • 想象一下你想使用“uniform mat4 m_model;”在片段着色器中。或者重新检查我的问题。我添加了几行以使这一点更清楚。
  • @Spektre:GL_ARB_explicit_uniform_location spec 明确指出:“每个透明的基本类型统一变量只使用一个位置,无论其类型如何。透明的基本类型,如定义在第 4.1 节中是布尔值、整数、浮点数、双精度数、向量和 矩阵。"
  • @Spektre:“你假设英特尔驱动程序的行为符合 GL 规范,我有很多次看到英特尔 gfx 驱动程序的不同行为与更新的东西......”那是一个驱动程序错误,你应该明确指出这是解决此类错误的方法。您应该建议(正如您在此处所做的那样)统一位置是字节偏移量
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 2014-09-25
  • 2011-06-05
  • 1970-01-01
相关资源
最近更新 更多