繁体   English   中英

将 OpenGL 渲染保存到图像文件

[英]Save OpenGL rendering to an image file

尽管 OpenGL 的作用很简单,但我仍然感到困惑,但我开始了解它的工作原理。

我正在寻找一个最小的屏幕外渲染示例来帮助我入门。

我的应用程序将获取一堆三角形和有关如何相对于相机定位它们的信息,并将渲染结果保存到图像文件中。 目前没有照明、材料或后期处理。

我看过有关创建屏幕外上下文、创建 FBO、渲染到纹理等的教程。我不介意使用 QT,因为它方便地提供了 OpenGL 工具、窗口和 QImage。 据我了解,为了能够对渲染图像进行图像处理,您需要将渲染目标设置为纹理,然后使用着色器,最后将纹理读取到数组中。

试图把事情放在一起从来没有让我找到一个好的起点。 我要么被困在设置依赖项上,要么黑屏,要么盯着那些除了我需要的东西做太多事情的项目。

更新 1:让它有点工作。

#include <QtGui/QGuiApplication>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFunctions_4_3_Core>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLShaderProgram>
#include <QDebug>
#include <QImage>
#include <QOpenGLBuffer>

int main(int argc, char* argv[])
{
   QGuiApplication a(argc, argv);

   QSurfaceFormat surfaceFormat;
   surfaceFormat.setMajorVersion(4);
   surfaceFormat.setMinorVersion(3);

   QOpenGLContext openGLContext;
   openGLContext.setFormat(surfaceFormat);
   openGLContext.create();
   if(!openGLContext.isValid()) return -1;

   QOffscreenSurface surface;
   surface.setFormat(surfaceFormat);
   surface.create();
   if(!surface.isValid()) return -2;

   openGLContext.makeCurrent(&surface);

   QOpenGLFunctions_4_3_Core f;
   if(!f.initializeOpenGLFunctions()) return -3;

   qDebug() << QString::fromLatin1((const char*)f.glGetString(GL_VERSION));

   QSize vpSize = QSize(100, 200);

   qDebug("Hi");

   QOpenGLFramebufferObjectFormat fboFormat;
   fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
   QOpenGLFramebufferObject fbo(vpSize, fboFormat);

   fbo.bind();

    // //////////


   static const float vertexPositions[] = {
       -0.8f, -0.8f, 0.0f,
        0.8f, -0.8f, 0.0f,
        0.0f,  0.8f, 0.0f
   };

   static const float vertexColors[] = {
       1.0f, 0.0f, 0.0f,
       0.0f, 1.0f, 0.0f,
       0.0f, 0.0f, 1.0f
   };

   QOpenGLBuffer vertexPositionBuffer(QOpenGLBuffer::VertexBuffer);
   vertexPositionBuffer.create();
   vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
   vertexPositionBuffer.bind();
   vertexPositionBuffer.allocate(vertexPositions, 9 * sizeof(float));

   QOpenGLBuffer vertexColorBuffer(QOpenGLBuffer::VertexBuffer);
   vertexColorBuffer.create();
   vertexColorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
   vertexColorBuffer.bind();
   vertexColorBuffer.allocate(vertexColors, 9 * sizeof(float));

   QOpenGLShaderProgram program;
   program.addShaderFromSourceCode(QOpenGLShader::Vertex,
                                   "#version 330\n"
                                   "in vec3 position;\n"
                                   "in vec3 color;\n"
                                   "out vec3 fragColor;\n"
                                   "void main() {\n"
                                   "    fragColor = color;\n"
                                   "    gl_Position = vec4(position, 1.0);\n"
                                   "}\n"
                                   );
   program.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                   "#version 330\n"
                                   "in vec3 fragColor;\n"
                                   "out vec4 color;\n"
                                   "void main() {\n"
                                   "    color = vec4(fragColor, 1.0);\n"
                                   "}\n"
                                   );
   program.link();
   program.bind();

   vertexPositionBuffer.bind();
   program.enableAttributeArray("position");
   program.setAttributeBuffer("position", GL_FLOAT, 0, 3);

   vertexColorBuffer.bind();
   program.enableAttributeArray("color");
   program.setAttributeBuffer("color", GL_FLOAT, 0, 3);

   f.glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
   f.glClear(GL_COLOR_BUFFER_BIT);

   f.glDrawArrays(GL_TRIANGLES, 0, 3);

   program.disableAttributeArray("position");
   program.disableAttributeArray("color");

   program.release();

   // ///////////////

   fbo.release();

   qDebug("FBO released");

   QImage im = fbo.toImage();

   if (im.save("asd.png")){
       qDebug("Image saved!!");
   }

   return 0;
}

保存的图像与 FBO 大小相同,颜色对应于 glClearColor 中设置的颜色,但不渲染三角形。 我错过了什么?

您可以在渲染和交换后使用glReadPixels

int* buffer = new int[ WIDTH * HEIGHT * 3 ];
...
glReadPixels( 0, 0, WIDTH, HEIGHT, GL_BGR, GL_UNSIGNED_BYTE, buffer );

然后您可以将buffer写入 .tga 文件:

FILE   *out = fopen(tga_file, "w");
short  TGAhead[] = {0, 2, 0, 0, 0, 0, WIDTH, HEIGHT, 24};
fwrite(&TGAhead, sizeof(TGAhead), 1, out);
fwrite(buffer, 3 * WIDTH * HEIGHT, 1, out);
fclose(out);

有一点晚。

由于正在使用 FBO,因此在fbo->release()将图像保存为 PNG 之前添加了以下代码。

QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
fb.save("/path_to_image_file/image_file.png", "PNG");

如果您想确保所有渲染完成,那么您可以在此之前执行以下操作:

QOpenGLContext::currentContext()->functions()->glFlush();

您可能还想将以下内容添加到 fbo 格式中:

fboFormat.setTextureTarget(GL_TEXTURE_2D);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM