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

标签 opengl graphics glsl shader

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

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

layout (location = ...)

句法?

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

It is illegal to assign the same uniform location to two uniforms in the same shader or the same program. Even if those two uniforms have the same name and type, and are defined in different shader stages, it is not legal to explicitly assign them the same uniform location; a linker error will occur.



以下引用来自 GLSL 规范:

No two default-block uniform variables in the program can have the same location, even if they are unused, otherwise a compile-time or link-time error will be generated.



我正在使用 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 规范的解释是正确的,这似乎与预期不同。虽然,这正是我希望它运行的方式。

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

最佳答案

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

    当您附加时 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);
        }
    

    片段着色器:
    // 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
  • 等等...
  • 关于OpenGL - 不同着色器阶段的显式统一位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32416889/

    相关文章:

    c++ - 避免每帧重新渲染 HUD/GUI 元素

    opengl - 在opengl中绘制体素(立方体)的最有效方法是什么?

    c - 使用单一光源渲染 3D 立方体的最简单方法是什么?

    c++ - 启用 MSAA 时,会出现伪影并且边缘上的纹理查找失败

    c - OpenGL 是否向后兼容 OpenGL ES?

    linux - 在 Linux 下从 wxGLCanvas 中初始化 Glew

    java - 无需任何外部 API 即可处理视频

    opengl - 正态分布函数中潜在活跃微面的集中度

    glsl - WebGL 2.0 最大图像纹理单位和最大组合纹理单位之间有什么区别?

    c++ - Vulkan 几何着色器意外崩溃