仅在错误的着色器程序中设置属性会影响属性值

Only setting the attribute in wrong shader program affects attribute value

本文关键字:属性 设置 影响 程序 错误      更新时间:2023-10-16
一旦

我尝试在 OpenGL 中使用多个着色器程序,我总是会遇到问题。出于某种原因,设置正在使用的 shader2 程序的属性根本没有反映 - 但在当前未使用的 shader1 中设置属性会影响 shader2 中的渲染。我确定,使用了我的 shader2(将着色器中的属性设置为常量值会反映在使用 shader2 绘制的对象上),并且我正在 shader2 中设置属性值。

我将ShaderPrograms封装到一个类中,如下所示:

class ShaderProgram{
public:
ShaderProgram(const std::string& vertexSource, const std::string& fragmentSource){
  vertexShader = glCreateShader(GL_VERTEX_SHADER);
  const GLchar *source = (const GLchar *)vertexSource.c_str();
  glShaderSource(vertexShader, 1, &source, 0);
  glCompileShader(vertexShader);
  fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  source = (const GLchar *)fragmentSource.c_str();
  glShaderSource(fragmentShader, 1, &source, 0);
  glCompileShader(fragmentShader);
  program = glCreateProgram();
  glAttachShader(program, vertexShader);
  glAttachShader(program, fragmentShader);
  glLinkProgram(program);
}
void use(){
  glUseProgram(program);
}
void setAttribPointer(const char* name, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) {
  GLuint pos = glGetAttribLocation(program, name);
  glEnableVertexAttribArray(pos);
  glVertexAttribPointer(pos, size, type, normalized, stride, pointer);
}
void setAttribValue4f(const char* name, float x, float y, float z, float w) {
  GLuint pos = glGetAttribLocation(program, name);
  glDisableVertexAttribArray(pos);
  const GLfloat pointer[] = { x, y, z, w };
  glVertexAttrib4fv(program, pointer);
}
~ShaderProgram() {
  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);
  glDeleteProgram(program);
}
private:
 GLuint vertexShader, fragmentShader, program;
};

我的应用程序中的渲染循环如下所示:

program1.use();
program1.setAttribValue4f("color", 1.0f, 0.0f, 0.0f, 1.0f);
program1.setAttribPointer("positions", 3, GL_FLOAT, GL_FALSE, 0, vertices.data());
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, indices.data());
program2.use();
program2.setAttribValue4f("color", 0.0f, 0.0f, 1.0f, 1.0f);
program2.setAttribPointer("positions", 3, GL_FLOAT, GL_FALSE, 0, vertices.data());
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, indices.data());

在这种情况下,两个对象都以红色绘制 - 而第二个对象应该是蓝色(在第二个着色器程序中,颜色属性设置为蓝色)。我可以使用任何简单的 GLSL 着色器重现此问题。但是,如果我将上面的代码更改为:

program1.use();
program1.setAttribValue4f("color", 1.0f, 0.0f, 0.0f, 1.0f);
program1.setAttribPointer("positions", 3, GL_FLOAT, GL_FALSE, 0, vertices.data());
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, indices.data());
program2.use();
program1.setAttribValue4f("color", 0.0f, 0.0f, 1.0f, 1.0f);
program2.setAttribPointer("positions", 3, GL_FLOAT, GL_FALSE, 0, vertices.data());
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, indices.data());

第二个对象以蓝色绘制(这就是我想要完成的)。但令人困惑的是,glVertexAttrib4fv(program, pointer);被调用在错误的程序对象(未使用),但颜色被更改 - 虽然它没有改变,如果我使用正确的程序对象 (program2)。我在 glUseProgram() 后和 glGetAttribLocation()/glVertexAttrib4fv() 之后检查了glGetError() - 总是返回 0。glGetAttribLocation()返回的位置也正确。GLSL是#version 330

知道什么可能导致此问题吗?

如果您不想设置每个顶点的颜色,请使用统一来传递该值。

另外,为什么要在setAttribValue4f中调用glDisableVertexAttribArray(pos)?

我在一个简单的打字错误中发现了我的问题。作为第一个参数,我将程序对象传递给glVertexAttrib4fv()而不是位置:

glVertexAttrib4fv(program, pointer);

应该是:

glVertexAttrib4fv(pos, pointer);

OpenGL使用弱类型(完全相同的类型GLuint用于完全不同的对象)这一事实使得很难找到这个错误。巧合的是,我的属性的位置是第一个程序的值(值为 1 的GLuint),这导致始终使用我在第一个程序中设置的属性(因为 eprogram 等于我想要设置的位置)。解决这个问题,为我解决了问题。

重要的是要记住,即顶点属性和着色器程序之间没有直接关系 - 规范说:

通用顶点属性索引与 顶点着色器中的用户定义属性变量是 程序对象的状态,但泛型顶点的当前值 属性不是。每个通用顶点属性的值是一部分 当前状态,即使不同的程序也会保持 对象被使用。