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

时间:2016-02-24 17:38:26

标签: c++ opengl glsl shader

一旦我尝试在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;
};

我的应用程序中的renderloop看起来像:

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),它就不会改变。我在glGetError()之后和glUseProgram() / glGetAttribLocation()之后检查了glVertexAttrib4fv() - 始终返回0. glGetAttribLocation()返回的位置也是正确的。 GLSL是#version 330

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

2 个答案:

答案 0 :(得分:0)

如果您不想设置每顶点颜色,请使用制服来传递值。

为什么在setAttribValue4f中调用glDisableVertexAttribArray(pos)?

答案 1 :(得分:0)

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

glVertexAttrib4fv(program, pointer);

应该是:

glVertexAttrib4fv(pos, pointer);

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

重要的是要牢记这一点 VertexAttributes和Shader程序之间没有直接关系 - the specification说:

  

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