I have a 3d scene which I can render on my display. However, in addition to rendering it to display, I would like to also be able to export the rendered scene, say once every 100 frames, as a image (say a JPG or PNG image), maybe saving it as a file somewhere on my machine.
I tried something like the following:
do{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffername);
drawScene();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
drawScene();
}while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS
I'm not sure if I'm using the FrameBuffer Objects correctly, but was looking for suggestions as to how to proceed given my goal. From the above code, I am binding the framebuffer to the FBO I have defined and then drawing the scene (which should draw to the FBO if I am correct?). Then I draw again to my regular display. However, this code causes the display to constantly switch between my scene, and an empty (black) scene, which I don't want. I want my scene to be displayed to the display device as a nice clean 3d scene, without constantly going all black.
My drawing function looks something like this:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glBindTexture(GL_TEXTURE_2D, 0);
//glBindFramebuffer(GL_FRAMEBUFFER, framebuffername);
// Use our shader
glUseProgram(programID);
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0); //DEFINE MODEL TO WORLD TRANSFORMATION
//glm::mat4 ModelMatrix = glm::scale(2.0,2.0,2.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniform1f(FARPLANE, farplane_control);
glUniform1f(NEARPLANE, nearplane_control);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::vec3 lightPos = glm::vec3(0, 0, 4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
1, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices.size());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glReadBuffer(GL_FRONT);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
Your drawScene()
code includes these lines at the end:
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
What do you think happens if you call this when you're not actually rendering to the screen?
The obvious solution is to include a flag in the function that instructs whether to perform the buffer swapping:
void drawScene(bool swap = true) {
/*...*/
if(swap) {
glfwSwapBuffers(window);
glfwPollEvents();
}
}
do{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffername);
drawScene(false);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
drawScene(true);
}while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS
Or, you could move those calls outside the function, which is probably better since it doesn't really make sense to make them local to your draw function in the first place.
do{
glfwPollEvents(); //Prefer having this be the first call, in case you need the window
//responding to user input immediately
glBindFramebuffer(GL_FRAMEBUFFER, framebuffername);
drawScene();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
drawScene();
glfwSwapBuffers(window); //No longer in drawScene() function
}while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS