即使我在着色器中使用了变量,glGetUniformLocation 仍返回 -1

Posted

技术标签:

【中文标题】即使我在着色器中使用了变量,glGetUniformLocation 仍返回 -1【英文标题】:glGetUniformLocation returns -1 even though I used the variable in shader 【发布时间】:2019-07-04 08:02:37 【问题描述】:

glsl 编译器似乎优化了未使用的变量(删除)。 在我的情况下,我使用了变量,但 glGetUniformLocation 返回 -1

rgbScene.addRenderStage(
    [&obj = std::as_const(model)](Camera* cam) 

    auto& mesh = std::get<Mesh>(obj);
    auto& program = std::get<ShaderProgram>(obj);

    glUseProgram(program);

    glBindVertexArray(mesh.getData<VAO>());
    int loc;
    glUniformMatrix4fv(
        loc = glGetUniformLocation(program, "proj_matrix"),
        1, GL_FALSE,
        glm::value_ptr(cam->getProjectionMatrix())
    );

    glUniformMatrix4fv(
        loc = glGetUniformLocation(program, "view_matrix"),
        1, GL_FALSE,
        glm::value_ptr(cam->getViewMatrix())
    );

    glUniformMatrix4fv(
        loc = glGetUniformLocation(program, "model_matrix"),
        1, GL_FALSE,
        glm::value_ptr(mesh.getModelMatrix())
    );

    glUniform3fv(
        loc = glGetUniformLocation(program, "light_direction"),
        1, glm::value_ptr(-(cam->getForward()))
    );

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.getData<VertexData>());
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.getData<NormalData>());
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

    glDrawArrays(GL_TRIANGLES, 0, mesh.getSize());

    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);
);

我通过在 Visual Studio 2019 中逐行调试来检查变量 loc,最后 glGetUniformLocation 返回 -1

这是我的顶点着色器代码

#version 460 core

uniform mat4 proj_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
uniform vec3 light_direction;

layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;

out VS_OUT

    vec3 N;
    vec3 L;
    vec3 V;
 vs_out;

void main(void)

    vec4 P = view_matrix * model_matrix * vec4(pos, 1.0);

    vs_out.N = mat3(view_matrix * model_matrix) * normal;
    vs_out.L = mat3(view_matrix) * (-light_direction);
    vs_out.V = -P.xyz;

    gl_Position = proj_matrix * P;

我尝试更改变量名称,不同的顺序...但无法解决此问题

shader中的uniform变量还有其他规则吗??

-- 编辑-- 对于片段着色器,

#version 460 core

layout (location = 0) out vec4 color;

in VS_OUT

    vec3 N;
    vec3 L;
    vec3 V;
 fs_in;

uniform vec3 diffuse_albedo = vec3(0.8, 0.3, 0.2);
uniform vec3 specular_albedo = vec3(0.7);
uniform float specular_power = 128.0;

void main(void)

    vec3 N = normalize(fs_in.N);
    vec3 L = normalize(fs_in.L);
    vec3 V = normalize(fs_in.V);

    vec3 R = reflect(-L, N);

    vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
    vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;

    color = vec4(diffuse + specular, 1.0);

    // color = vec4(1.0,1.0, 1.0, 1.0);

【问题讨论】:

是否也给片段着色器“使用”输入NLV?注意,活动资源是在程序链接时确定的。如果片段着色器的输入未使用,则在顶点着色器中设置相应输出变量的制服可能不会变为活动状态。 @Rabbid76 我添加了片段着色器。 编译器是否有可能只是省略了对loc 的赋值,因为之后再也不会使用它? 【参考方案1】:

片段着色器输入NLV 变量也必须“使用”

注意,活动资源是在程序链接时确定的。如果片段着色器的输入未使用,则在顶点着色器中设置相应输出变量的制服可能不会变为活动状态。

参见OpenGL 4.6 Core Profile Specification - 7.3.1 Program Interfaces,第 102 页:

7.3.1 程序接口

当一个程序对象成为当前渲染状态的一部分时,它的可执行代码可以通过各种接口与其他 GL 管道阶段或应用程序代码进行通信。当一个程序被链接时,GL 为每个接口构建一个活动资源列表。活动资​​源的示例包括着色器代码使用的变量、接口块和子例程。 着色器代码中引用的资源被认为是活动的,除非编译器和链接器可以最终确定它们对程序的可执行代码产生的结果没有可观察到的影响。例如,如果变量被声明但未在可执行代码中使用、仅在永远不会执行的 if 语句的子句中使用、仅在从未调用的函数中使用或仅用于临时计算对任何着色器输出没有影响的变量。在编译器或链接器无法做出决定性决定的情况下,着色器代码引用的任何资源都将被视为处于活动状态。任何接口的活动资源集都是依赖于实现的,因为它依赖于编译器和链接器执行的各种分析和优化

如果一个程序链接成功,GL将根据链接产生的可执行代码生成活动资源列表。

【讨论】:

谢谢@Rabbid76 ...为了测试,我在片段着色器的最后添加了color = vec4(1.0, 1.0, 1.0, 1.0);,似乎编译器优化了片段着色器的整个代码,除了color = vec4(1.0, 1.0, 1.0, 1.0);,因为其他代码没有用于计算片段着色器的输出。 bool valid = glGetError() == GL_NO_ERRORglUseProgram(program) 之前和glUseProgram(program); 之后返回true,glGetError() == GL_NO_ERROR 变为false。你知道为什么会出错吗?我的program 似乎找到了。是因为 lambda 还是 functor?? @신준섭 很抱歉,但不能说,只看到这个 (lambda) 函数。请注意,glGetError 返回不同的错误类型,glUseProgram 可能导致错误的原因也不同。无论如何,我建议激活Debug Output 以查找 OpenGL 错误。 谢谢!很多!!

以上是关于即使我在着色器中使用了变量,glGetUniformLocation 仍返回 -1的主要内容,如果未能解决你的问题,请参考以下文章

此顶点着色器中的统一浮动不起作用

在 vertexShader 中使用 OpenGl 未声明的标识符,我在顶点着色器中绘制三角形时遇到问题

为什么我在GLSL着色器中看到这些混合工件?

为啥我在 Unity RayMarching 着色器中出现 for-loop 错误?

跨多个着色器的 OpenGL 统一

从 GLSL 着色器中获取常量