如何解决在未使用的着色器中设置统一会影响输出
我正在学习 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);
}
}
这是(期望的)输出:
在此之前,我有一个单独的天空盒着色器。在代码中,我为这个着色器留下了“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 后面只是对 glGetUniformlocation
和 gluniform...
的调用。我还确保确认两个程序 ID 不相同,它们也不同。如果我取消注释 skyBoxShader
的 setter 调用,它会按需要工作。 (实际上只是 view
矩阵导致了这种效果。)我还尝试为制服提供单独的名称,但这没有区别。
我想知道为什么会发生这种情况。如果您需要,我会提供更多信息。
PS:我最近读到片段着色器中对 texture()
的调用应该发生在分支之外。但在这种情况下,两种参数类型都不同(samplerCube
和 vec3
与 sampler2D
和 vec2
),所以我不确定在这种情况下是否可行。>
编辑:这是 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 举报,一经查实,本站将立刻删除。