在未使用的着色器中设置制服会影响输出
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 后面只是对 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...)
,在当前shader中设置location 1,也就是challengeShader,也就是uView。看到问题了吗?
glUniformWhatever
始终更新当前使用的着色器程序中的制服。如果你想在不同的着色器程序中设置制服,你必须先使用它,或者使用 glProgramUniformWhatever
代替 (OpenGL 4.1+)
我正在学习 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 后面只是对 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...)
,在当前shader中设置location 1,也就是challengeShader,也就是uView。看到问题了吗?
glUniformWhatever
始终更新当前使用的着色器程序中的制服。如果你想在不同的着色器程序中设置制服,你必须先使用它,或者使用 glProgramUniformWhatever
代替 (OpenGL 4.1+)