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

Hen*_*nkk 7 opengl graphics shader glsl

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

使用自动分配时,当标识符匹配时,将不同阶段的制服分配到同一位置.但是如何使用the定义着色器中的位置

layout (location = ...)
Run Code Online (Sandbox Code Playgroud)

句法?

以下引用自: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() { ... }
Run Code Online (Sandbox Code Playgroud)

片段着色器:

#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() { ... }
Run Code Online (Sandbox Code Playgroud)

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

但是,当不使用制服时,存在制服重叠的问题.

Spe*_*tre 3

请参阅C++ 中的完整 GL+VAO/VBO+GLSL+着色器示例

  • 从该示例中提取:

GPU端:

#version 400 core
layout(location = 0) in vec3 pos;
Run Code Online (Sandbox Code Playgroud)
  • 你需要指定 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);
Run Code Online (Sandbox Code Playgroud)

当你附加datalocation

那么您需要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);
    }
Run Code Online (Sandbox Code Playgroud)

片段着色器:

// 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);
    }
Run Code Online (Sandbox Code Playgroud)

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

  • #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);
Run Code Online (Sandbox Code Playgroud)

或者定义的位置:

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);
Run Code Online (Sandbox Code Playgroud)

看起来nVidia编译器以不同的方式处理这些位置。如果它无法正常工作,请尝试针对有缺陷的驱动程序的解决方法,以根据数据类型设置不同步骤的位置:

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

  • @Spektre:[`GL_ARB_explicit_uniform_location`规范](https://www.opengl.org/registry/specs/ARB/explicit_uniform_location.txt)明确指出:“每个透明基本类型统一变量**仅消耗一个位置,无论它的类型**。第 4.1 节中定义的透明基本类型是布尔值、整数、浮点数、双精度数、向量和**矩阵**。” (3认同)
  • 遗憾的是,这仅描述了有关属性的情况,而不是制服的情况。该示例甚至没有使用统一的位置。 (2认同)
  • @Spektre:“您假设英特尔驱动程序的行为符合 GL 规范,我多次在具有更新内容的英特尔 gfx 驱动程序上看到不同的行为......”那么这是一个驱动程序错误,您应该明确指出这是此类问题的解决方法一个错误。您不应该建议(正如您的答案在这里所做的那样)统一位置是*字节偏移量*。 (2认同)