在未使用的着色器中设置制服会影响输出

Setting uniforms in an unused shader affects output

我正在学习 OpenGL,我偶然发现了一个我不确定为什么会发生的问题。我有一个着色器(顶点+片段),我为其设置了统一变量。着色器负责绘制天空盒和对象(它通过 uIsSkybox uniform 变量区分)。这是每个的代码:

#version 330 core 

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

out vec2 oObjTexCoords;
out vec3 oSkyboxTexCoords; 

uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;

uniform bool uIsSkybox;

void main()
{
    if(uIsSkybox)
    {
        mat4 mvp = uProjection * mat4(mat3(uView)) * uModel;
        oSkyboxTexCoords = aPos;
        vec4 pos = mvp * vec4(aPos, 1.0);
        gl_Position = pos.xyww;
    }
    else 
    {
        mat4 mvp = uProjection * uView * uModel;
        oObjTexCoords = aTexCoords;
        gl_Position = mvp * vec4(aPos, 1.0);
    }
}

#version 330 core 

struct Material {
    sampler2D texture_diffuse;
    sampler2D texture_specular;
    float shininess;
};

in vec2 oObjTexCoords;
in vec3 oSkyboxTexCoords; 

out vec4 fragColor;

uniform Material material;
uniform sampler2D texture_diffuse1;
uniform samplerCube uSkyboxSampler;

uniform bool uIsSkybox;

void main() 
{
    if(uIsSkybox)
    {
        fragColor = texture(uSkyboxSampler, oSkyboxTexCoords);
    }
    else 
    {
//      fragColor = texture(texture_diffuse1, oObjTexCoords);
        fragColor = texture(material.texture_diffuse, oObjTexCoords);
    }

}

这是(期望的)输出:

在此之前,我有一个单独的天空盒着色器。在代码中,我保留了此着色器的“setUniforms”代码,仅删除了它的用法 (glUseProgram)。我认为这就足够了,因为无论如何都没有使用着色器。但是,它确实影响了我的天空盒,我不确定为什么。

model = glm::mat4(1.0f);
challengeShader.use();
challengeShader.setBool("uIsSkybox", true);
challengeShader.setMat4("uModel", model);
challengeShader.setMat4("uView", view);
challengeShader.setMat4("uProjection", projection);


//skyboxShader.use();
skyboxShader.setMat4("uModel", model);
skyboxShader.setMat4("uView", view);
skyboxShader.setMat4("uProjection", projection);

在 setter 后面只是对 glGetUniformLocationglUniform... 的调用。我还确保确认两个程序 ID 不相同,而且它们不相同。如果我取消注释 skyboxShader 的 setter 调用,它会按预期工作。 (实际上只是造成这种效果的 view 矩阵。)我也尝试给制服单独命名,但这没有什么区别。

我想知道为什么会这样。如果您需要,我会提供更多信息。

PS:我最近读到片段着色器中对 texture() 的调用应该发生在分支之外。但在这种情况下,两种参数类型都不同(samplerCubevec3sampler2Dvec2),所以我不确定在这种情况下是否可行。

编辑:这是 setMat4 的代码:

void Shader::setMat4(const std::string& name, glm::mat4 value) const {
    int location = glGetUniformLocation(ID, name.c_str());
    glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}

挑战着色器有制服:

  • 位置 0(可能):uModel
  • 位置1(可能):uView
  • 位置 2(可能):uProjection
  • 位置 3(可能):uIsSkybox
  • ...等等...

天空盒着色器也是如此 - 假设它们的顺序不同:

  • 位置 0(例如):uProjection
  • 位置 1(例如):uModel
  • 位置2(举例):uView
  • ...等等...

当您执行 skyboxShader.setMat4("uModel", model); 时,它会调用 glGetUniformLocation(skyboxShader.ID, "uModel") 告诉您 uModel 在 skyboxShader 中的位置 1。然后调用glUniformMatrix4fv(1, ...etc...),在当前shader中设置location 1,也就是challengeShader,也就是uView。看到问题了吗?

glUniformWhatever 始终更新当前使用的着色器程序中的制服。如果你想在不同的着色器程序中设置制服,你必须先使用它,或者使用 glProgramUniformWhatever 代替 (OpenGL 4.1+)