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

2023-12-15

我正在尝试制作一个简单的离屏渲染器来使用 QT 生成一堆图像文件。周围有很多例子,但我还没有找到任何处理这种一次性渲染的例子,没有循环,也没有可见窗口。另外,QT 为您提供了方便的包装器,这很好,但另一方面,遵循使用 C++glew+glfw 编写的示例变得更加困难。

我尝试使用this设置屏幕外上下文并且它可以工作。创建 FBO 并渲染后(例如here)图像内没有绘制三角形(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();
}

有关于如何将屏幕外部分与绘图部分放在一起的 ide23edas 吗?

更新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的提示。 这是一个工作代码,可以为任何感兴趣的人保存彩色三角形的图像。


我怀疑问题很简单,您获得了 4.3 核心配置文件,但没有创建/使用顶点数组对象。绑定着色器程序后立即创建 VAO 就足够了,因此更改...

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

to...

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

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

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

另请注意,错误检查很重要。考虑使用glGetError或者也许是一个调试上下文.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 QT 进行最小 OpenGL 离屏渲染 的相关文章

随机推荐

  • 在 C++ 中创建稀疏数组的最佳方法是什么?

    我正在研究一个需要操作巨大矩阵的项目 特别是用于连接计算的金字塔求和 简而言之 我需要跟踪矩阵 多维数组 中大量零的相对少量的值 通常为 1 在极少数情况下超过 1 稀疏数组允许用户存储少量值 并假设所有未定义的记录都是预设值 由于物理上不
  • PHP 显示中文字符:SET NAMES 'utf8' 不起作用

    我正在尝试使用我拥有的数据库 但无法在其中显示中文字符 数据库实际上首先是一个 MS Access 文件 我用程序将其转换为 mysql 无论如何 很多行中都有中文字符 我无法让它们在任何浏览器中正确显示 否则我可以很好地显示汉字 如果我使
  • 配置旁遮普向 Openfire 发送 xmpp 请求

    我正在尝试将旁遮普连接管理器与 Openfire 一起使用 我已经有一个正在运行的 Openfire 服务器 我还安装了 punjab 并且服务器正常启动 允许我导航到本地主机上的端口 5280 虽然http localhost 5280
  • 将整数和文本字符串等数据从手机发送到网络数据库

    我有一个项目 我应该将整数 浮点数和文本字符串等数据从 Android 应用程序发送到 Web 数据库 但是我不知道如何做到这一点 有人可以解释一下吗 任何建议或帮助将不胜感激 您需要编写一些服务器端逻辑 通过POST或GET方法接受参数k
  • 使用角度2中的viewchild更新元素的innerhtml

    我有像这样的html元素 section class span title span span class value span section 我使用访问组件中的元素 ViewChild hiddenElement hiddenEleme
  • 在 ftp 服务器中不递归地列出文件、目录、子文件和子目录的想法

    我正在尝试生成 ftp 服务器中给定目录及其子目录的文件列表 服务器工作正常 我已经成功地生成了当前目录的文件列表 当我尝试列出子目录及其文件时 事情就变得复杂了 我被要求不要使用递归算法 所以我自己做了一些研究 我尝试过使用线程 对于找到
  • FutureTask 获取与运行,任务永远不会完成

    我正在学习 Callables 并决定制作一个非常简单的程序 问题是当我调用 getFutureTask 时线程被阻塞 Thread State TIMED WAITING 在对象监视器上 您能否告诉我为什么会这样以及为什么当我在 futu
  • 替换字符串中字符的实例

    这个简单地尝试用冒号替换分号 在特定位置 的简单代码不起作用 for i in range 0 len line if line i and i in rightindexarray line i 它给出了错误 line i TypeErr
  • 当“OrdinalBase”字段设置为 1 时,“kernel32.dll”如何导出序数 0?

    查看加载到内存中的 kernel32 dll 我看到以下导出序数表 gdb x 400hd eax 0x776334b0
  • 通过 shell 脚本拒绝 cat 的权限[重复]

    这个问题在这里已经有答案了 我在 bin rclone sync ACD log 中的日志文件上的 shell 脚本中运行 cat 时遇到问题 这是 shell 脚本中的行 RESULT cat LOGFILE tail 1 但是当运行脚本
  • 时区代码到时区信息

    在我们的 MS Dynamics CRM 项目中 我们创建了一个海量用户上传批次 该批处理从 Excel 文件读取并批量上传用户 该批次需要设置的内容之一是时区代码 在 Excel 文件中 时区将写为 UTC 1 CRM 使用的代码似乎是
  • 查找数组中最接近的值

    int array new int 5 5 7 8 15 20 int TargetNumber 13 对于目标数字 我想找到数组中最接近的数字 例如 当目标数字为 13 时 上面数组中最接近它的数字是 15 我如何在 C 中以编程方式实现
  • Linux打开设备时串口缓冲区不为空

    我有一个系统 我在串行端口上看到了我意想不到的奇怪行为 我以前曾在 USB 转串口适配器上偶尔看到过这种情况 但现在我也在本机串行端口上看到过这种情况 而且频率要高得多 该系统被设置为运行自动化测试 并且将首先执行一些任务 这些任务会导致在
  • 如何在ios模拟器中安装IPA?

    我建了一个 ipa使用后Xcode存档然后分发为ad hoc通常我会将其复制到真实的 ios 设备 但今天它失败了 说 安装失败 问题是使用 xcode gt 窗口 gt 设备和模拟器 不向我显示正在运行的模拟器 我有一个正在运行的 ios
  • 如何使用 eventBus 作为总线来将更新传递给 Vue 组件中的视图?

    监听组件 b 中总线的自定义事件 然而 在组件a中分派事件后 它访问组件b 执行了组件b的监听函数 但是msg数据功能未更新 请不要说Vuex 相关代码基于Vue CLi3 这里的代码 A组份
  • Bash 脚本检查图像是否为动画 png (apng)

    试图在我的 bash 脚本中找出一种方法来检查文件是否是动画 PNG apng 文件 就我而言 如果是的话 我想忽略它 有任何想法吗 更新 下面使用 pngcheck 的答案允许我检查图像是否是动画 此外 我还会检查文件的大小 如果它 大
  • 如何在给定鼠标坐标的情况下检测重叠(旋转)的 DOM 元素?

    我使用以下脚本来获取鼠标单击坐标处重叠的 DIV 元素的列表 在此示例中 如果 DIV 未旋转 则脚本可以正常工作 http jsfiddle net eyxt2tt1 2 If I apply a rotation在 DIV 上并用户单击
  • 为什么可组合对象看似无状态(唯一传递的参数是函数,而不是状态),但会进行重组

    我通过单击第一个可组合项调用相应的函数来更新 uiState 第二个可组合项因此而重组 尽管它不采用任何状态参数 只采用另一个函数 class MainActivity ComponentActivity override fun onCr
  • 如何使用 Sphinx 记录特定部分中的成员?

    我正在努力弄清楚如何将 Python 类的特定成员的文档放置在 Sphinx 文档的特定部分中 理想情况下 同时在另一个部分中自动记录其余部分 我有一个Python课程 class MyClass object def funky self
  • 使用 QT 进行最小 OpenGL 离屏渲染

    我正在尝试制作一个简单的离屏渲染器来使用 QT 生成一堆图像文件 周围有很多例子 但我还没有找到任何处理这种一次性渲染的例子 没有循环 也没有可见窗口 另外 QT 为您提供了方便的包装器 这很好 但另一方面 遵循使用 C glew glfw