微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决在未使用的着色器中设置统一会影响输出

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

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

}

这是(期望的)输出

Correct output

在此之前,我有一个单独的天空盒着色器。在代码中,我为这个着色器留下了“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);

Incorrect output

在这些 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...),在当前着色器中设置位置1,即challengeShader,即uView。看到问题了吗?

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。