一旦我尝试在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
知道什么可能导致这个问题吗?
答案 0 :(得分:0)
如果您不想设置每顶点颜色,请使用制服来传递值。
为什么在setAttribValue4f中调用glDisableVertexAttribArray(pos)?
答案 1 :(得分:0)
我在一个简单的输入错误中发现了我的问题。作为第一个参数,我将程序对象传递给glVertexAttrib4fv()
而不是位置:
glVertexAttrib4fv(program, pointer);
应该是:
glVertexAttrib4fv(pos, pointer);
OpenGL使用弱类型(相同类型GLuint
用于完全不同的对象)这一事实使得很难找到这个错误。巧合的是,我的属性的位置是作为第一个程序的值(GLuint
,其值为1),这导致始终使用我在第一个程序中设置的属性(因为eprogram等于我想要的位置)设置)。解决这个问题,为我解决了这个问题。
重要的是要牢记这一点 VertexAttributes和Shader程序之间没有直接关系 - the specification说:
通用顶点属性索引与a之间的绑定 顶点着色器中的用户定义属性变量是其中的一部分 程序对象的状态,但是通用顶点的当前值 属性不是。每个通用顶点属性的值是部分 当前状态,即使是不同的程序也保持不变 使用了对象。