我刚刚开始尝试学习opengl,并且正在将代码的各个部分分离到我遇到问题的类中。
这是一个非常简单的问题。在下面的代码中,如果Mesh构造函数底部的glBindVertexArray(0)
被注释掉,它会将图像绘制到屏幕上,但如果我将其放入,则不会绘制图像。
在glBindVertexArray(vao)
函数的glDrawElements
调用之前有一个Mesh.draw()
命令,所以看起来它应该可行,但它没有。
主要代码:
int main(int argc, char*argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0)
std::cout << "SDL did not intizlize. SDL Error: " << SDL_GetError() << std::endl;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_Window* window = SDL_CreateWindow("OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
SDL_GLContext context = SDL_GL_CreateContext(window);
glewExperimental = GL_TRUE;
GLenum glewTest = glewInit();
if (glewTest != GLEW_OK)
std::cout << glewGetErrorString(glewTest) << std::endl;
std::cout << glGetError() << std::endl;
Mesh mesh;
Shaders shaders("basicShader");
Texture texture("kitten.png");
//Loop stuff
bool quit = false;
SDL_Event e;
double frameCounter = 0;
double time = SDL_GetTicks();
while (!quit) {
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
quit = true;
}
if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_ESCAPE)
quit = true;
}
}
++frameCounter;
if (SDL_GetTicks() - time >= 500) {
std::cout << "FPS: " << frameCounter / ((SDL_GetTicks() - time) / 1000) << std::endl;
frameCounter = 0;
time = SDL_GetTicks();
}
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
mesh.draw();
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Swap buffers
SDL_GL_SwapWindow(window);
}
mesh.~Mesh();
SDL_GL_DeleteContext(context);
SDL_Quit();
return 0;
}
网格类代码:
Mesh::Mesh() {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0, 0.0,
0.5f, 0.5f, 1.0, 0.0,
0.5f, -0.5f, 1.0, 1.0,
-0.5f, -0.5f, 0.0, 1.0
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &ebo);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
//glBindVertexArray(0);
}
void Mesh::draw() {
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glBindVertexArray(0);
}
Mesh::~Mesh() {
glDeleteVertexArrays(1, &vao);
}
我也没有在此处发布着色器设置代码,调用glVertexArrayPointer()
和glEnableVertexAttribArray()
来设置顶点属性。
答案 0 :(得分:3)
问题在于您在设置着色器时进行的glVertexAttribPointer()
和glEnableVertexAttribArray()
调用。这两个调用都会修改当前VAO的状态。
如果你打电话:
glBindVertexArray(0);
在设置网格结束时,0现在是您当前的VAO(兼容性配置文件中的合法VAO,但不在核心配置文件中)。因此,在此之后调用glVertexAttribPointer()
和glEnableVertexAttribArray()
将调用VAO 0中的状态。
当您在draw()
方法开始时调用绑定VAO时:
glBindVertexArray(vao);
您正在使用网格VAO中的所有状态。这反过来意味着您没有使用您在VAO 0中设置的状态。由于您在绑定网格VAO时从未进行glVertexAttribPointer()
和glEnableVertexAttribArray()
调用,因此现在根本没有设置顶点属性。
当你没有在构造函数结束时解开VAO时,你真的很幸运。由于在设置着色器时网格VAO仍然绑定,glVertexAttribPointer()
和glEnableVertexAttribArray()
调用修改了网格VAO状态,从而产生了所需的结果。但如果您使用多个网格/着色器,这很可能会失败。
您需要在设置网格时设置顶点状态,同时绑定特定网格的VAO。以下调用都修改VAO状态,并且必须在绑定正确的VAO时进行:
glEnableVertexAttribArray(...)
glDisableVertexAttribArray(...)
glVertexAttribPointer(...)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
在设置着色器程序时修改顶点设置状态在概念上也是有问题的。顶点设置状态不是着色器程序状态的一部分。