OpenGL:渲染到帧缓冲以及显示

时间:2017-11-01 16:14:06

标签: c++ opengl glfw glm-math fbo

我有一个可以在显示器上渲染的3D场景。但是,除了渲染它以显示之外,我还希望能够将渲染的场景(例如每100帧一次)导出为图像(比如JPG或PNG图像),也许可以将其保存为我的某处文件。机。

我尝试过以下内容:

do{
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffername);
    drawScene();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    drawScene();
}while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS

我不确定我是否正确使用了FrameBuffer对象,但正在寻找有关如何继续实现目标的建议。从上面的代码中,我将framebuffer绑定到我定义的FBO,然后绘制场景(如果我是正确的,应该绘制到FBO?)。然后我再次画到常规显示器上。但是,此代码会使显示屏在我的场景和空白(黑色)场景之间不断切换,这是我不想要的。我希望我的场景能够作为一个漂亮干净的3D场景显示在显示设备上,而不会一直变黑。

我的绘图功能看起来像这样:

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();
}

1 个答案:

答案 0 :(得分:3)

您的drawScene()代码最后包含以下这些代码:

// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();

如果您在未实际渲染到屏幕时调用此内容,您认为会发生什么?

显而易见的解决方案是在函数中包含一个指示是否执行缓冲区交换的标志:

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

或者,你可以将这些调用移到函数之外,这可能更好,因为首先让它们在你的绘制函数中是本地的并不是真的有意义。

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