Reputation: 1
I'm just starting out trying to learn opengl, and in the process of decoupling various parts of the code into classes I'm running into issues.
This is a pretty simple question. In the following code, it draws the image to the screen if the glBindVertexArray(0)
at the bottom of the Mesh constructor is commented out, but the image is not drawn if I put it in.
There is a glBindVertexArray(vao)
command RIGHT before the glDrawElements
call in the Mesh.draw()
function, so it seems like it should work, but it doesn't.
Main code:
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 class code:
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);
}
I also have shader setup code not posted here, which calls glVertexArrayPointer()
and glEnableVertexAttribArray()
to set up the vertex attributes.
Upvotes: 0
Views: 1116
Reputation: 54642
The problem is with the glVertexAttribPointer()
and glEnableVertexAttribArray()
calls that you make while setting up your shader. Both of these calls modify state of the current VAO.
If you call:
glBindVertexArray(0);
at the end of setting up your mesh, 0 is now your current VAO (which is a legal VAO in the Compatibility Profile, but not in the Core Profile). So calls to glVertexAttribPointer()
and glEnableVertexAttribArray()
you make after this will now modify the state in VAO 0.
When you make the call to bind your VAO at the start of your draw()
method:
glBindVertexArray(vao);
you're using all the state in your mesh VAO. Which in turn means that the state you set up in VAO 0 is not used. Since you never made glVertexAttribPointer()
and glEnableVertexAttribArray()
calls while your mesh VAO was bound, the vertex attributes are now not set up at all.
You were really just lucky that it worked when you did not unbind the VAO at the end of the constructor. Since the mesh VAO was still bound while you set up your shader, the glVertexAttribPointer()
and glEnableVertexAttribArray()
calls modified your mesh VAO state, which produced the desired result. But this would most likely fail miserably if you ever use more than one mesh/shader.
You really need to set up the vertex state while you set up your mesh, while the VAO for the specific mesh is bound. The following calls all modify VAO state, and must be made while the correct VAO is bound:
glEnableVertexAttribArray(...)
glDisableVertexAttribArray(...)
glVertexAttribPointer(...)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
Modifying vertex setup state while setting up a shader program is also conceptually questionable. The vertex setup state is not part of the shader program state.
Upvotes: 3