使用QT进行最小化的OpenGL离屏渲染

3
我正在尝试使用QT制作一个简单的离屏渲染器,以生成一堆图像文件。虽然有很多示例可用,但我还没有找到任何处理这种一次性渲染的示例,没有循环和没有可见窗口。此外,QT为您提供了方便的包装器,这很好,但另一方面,使用C++glew+glfw编写的示例变得更加难以理解。
我尝试使用这个来设置离屏上下文,并且它有效。创建FBO并进行渲染(就像这里),但在图像中没有画出三角形(fbo->ToImage)。
我的当前代码只是两者的混合:
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLShaderProgram>
#include <QApplication>
#include <QDebug>
#include <QImage>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>

int main(int argc, char* argv[])
{
   QApplication 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);

   QSize vpSize = QSize(300, 300);

   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\r\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\r\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);

   openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
   openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   openGLContext.functions()->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!!");
   }



   a.exec();
}

您有没有关于如何将屏幕外部分与绘图部分组合在一起的任何想法?

更新1:

#include <QGuiApplication>
#include <QOffscreenSurface>
#include <QOpenGLFunctions>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QDebug>
#include <QImage>
#include <QLoggingCategory>

int main(int argc, char* argv[])
{
    QGuiApplication a(argc, argv);
//    QLoggingCategory::setFilterRules("qt.qpa.gl=true");

//   =======CONTEXT SETUP======

//   Set OpenGL version to use
    QSurfaceFormat surfaceFormat;
    surfaceFormat.setMajorVersion(4);
    surfaceFormat.setMinorVersion(3);

    QOpenGLContext openGLContext;
    openGLContext.setFormat(surfaceFormat);
    openGLContext.create();
    if(!openGLContext.isValid()) qDebug("Unable to create context");

    QOffscreenSurface surface;
    surface.setFormat(surfaceFormat);
    surface.create();
    if(!surface.isValid()) qDebug("Unable to create the Offscreen surface");

    openGLContext.makeCurrent(&surface);

//   Viewport size
    QSize vpSize = QSize(300, 300);

    QOpenGLFramebufferObjectFormat fboFormat;
    fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
    QOpenGLFramebufferObject fbo(vpSize, fboFormat);
    openGLContext.functions()->glViewport(0,0,vpSize.width(), vpSize.height());
    fbo.bind();

//    ========GEOMEETRY SETUP========

    static const float vertexPositions[] = {
        -1.0f, -1.0f,
        -0.0f,  1.0f,
         1.0f, -1.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, 6 * 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\r\n"
                                   "in vec2 position;\n"
                                   "in vec3 color;\n"
                                   "out vec3 fragColor;\n"
                                   "void main() {\n"
                                   "    fragColor = color;\n"
                                   "    gl_Position = vec4(position, 0.0, 1.0);\n"
                                   "}\n"
                                   );
    program.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                   "#version 330\r\n"
                                   "in vec3 fragColor;\n"
                                   "out vec4 color;\n"
                                   "void main() {\n"
                                   "    color = vec4(fragColor, 1.0);\n"
                                   "}\n"
                                   );
    program.link();
    program.bind();

    QOpenGLVertexArrayObject vao;
    vao.create();
    vao.bind();

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

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

//    ==============DRAWING TO THE FBO============

    openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
    openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    openGLContext.functions()->glDrawArrays(GL_TRIANGLES, 0, 3);

//   =============CLEANUP================== maybe not necessary
    program.disableAttributeArray("position");
    program.disableAttributeArray("color");
    program.release();
    fbo.release();

//    ========SAVE IMAGE===========

    QImage im = fbo.toImage();

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

    a.quit();
}

感谢G.M的提示。 以下是一份能够保存彩色三角形图片的可工作代码,供有兴趣者参考。


请编辑您的问题以提供一个 [mcve]。目前情况下,我们只能猜测。 - G.M.
1个回答

0

我怀疑问题很简单,就是您得到了一个4.3核心配置文件,但没有创建/使用顶点数组对象。在绑定着色器程序后立即创建VAO应该就足够了,所以请更改...

program.link();
program.bind();

到...

program.link();
program.bind();

QOpenGLVertexArrayObject vao;
vao.create();
vao.bind();

(你还需要在源文件顶部添加#include <QOpenGLVertexArrayObject>。)

另外注意错误检查很重要。考虑使用glGetError或者一个调试上下文


哇!!它起作用了。你让我的一天变得光明起来了。我想清理代码并发布一些易于跟踪的东西。"openGLContext.functions()->"是调用OpenGL函数的正确方式吗?为了调试,"QLoggingCategory::setFilterRules("qt.qpa.gl=true");" 有用吗?谢谢。 - canaldin
@canaldin,你有没有在这方面发表过任何内容?使用OpenGL和QTOffscreenSurface进行离屏渲染的指南将填补互联网上的一个空缺 :) - Geronimo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接