Search code examples
c++openglglslshader

glGetUniformLocation returns -1 even though I used the variable in shader


It seems that the glsl compiler optimizes unused variable (remove). In my case I used the variable but the glGetUniformLocation returns -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);
});

I checked variable loc by debuging line by line in Visual Studio 2019 and at the last glGetUniformLocation returns -1

here's my vertex shader code

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

I tried changing the variable name, different order... but cannot fixed this problem

Is there any other rules for uniform variable in shader??

-- Edit -- for fragment shader,

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

Solution

  • The fragment shader inputs N, L and V variables have to be "used", too.

    Note, the active resources are determined when the program is linked. If an input to the fragment shader is unused, the uniforms which set the corresponding output variable in the vertex shader may not become active.

    See OpenGL 4.6 Core Profile Specification - 7.3.1 Program Interfaces, page 102:

    7.3.1 Program Interfaces

    When a program object is made part of the current rendering state, its executable code may communicate with other GL pipeline stages or application code through a variety of interfaces. When a program is linked, the GL builds a list of active resources for each interface. Examples of active resources include variables, interface blocks, and subroutines used by shader code. Resources referenced in shader code are considered active unless the compiler and linker can conclusively determine that they have no observable effect on the results produced by the executable code of the program. For example, variables might be considered inactive if they are declared but not used in executable code, used only in a clause of an if statement that would never be executed, used only in functions that are never called, or used only in computations of temporary variables having no effect on any shader output. In cases where the compiler or linker cannot make a conclusive determination, any resource referenced by shader code will be considered active. The set of active resources for any interface is implementation-dependent because it depends on various analysis and optimizations performed by the compiler and linker

    If a program is linked successfully, the GL will generate lists of active resources based on the executable code produced by the link.