【问题标题】:Add render target to default framebuffer of QOpenGLWidget将渲染目标添加到 QOpenGLWidget 的默认帧缓冲区
【发布时间】:2018-11-29 07:35:16
【问题描述】:

我想向 QOpenGLWidget 的默认帧缓冲区添加第二个渲染目标。

原因是我想实现对象拾取并通过将分割掩码渲染到gl_FragData[1] 来检查用户是否击中了对象。不幸的是,您只能从小部件中检索GLuint 句柄,并且没有QOpenGLFramebufferObject 的构造函数接收该句柄,并且没有其他选项可以检索帧缓冲区。

是否有可能在没有变通方法的情况下将另一个纹理附加到小部件的默认帧缓冲区?

我能想到的只有两个选项:

1. 在初始化时使用原生 OpenGL 调用(我宁愿坚持纯 Qt)附加纹理(当然我会存储 segmentationTexture 以便以后删除它):

glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
QOpenGLTexture *segmentationTexture = new QOpenGLTexture(QOpenGLTexture::BindingTargetBuffer);
// set texture parameters
segmentationTexture.create();
segmentationTexture.bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, segmentationTexture.textureId(), 0);
segmentationTexture.release();

然后在paintGL()

GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, buffers);

在 OpenGL 绘制调用之前并使用 glReadBuffer(GL_COLOR_ATTACHMENT1);gl_FragData[1] 检索内容。或者,如果这不起作用,则仅使用本机 OpenGL 代码来生成纹理。

2. 创建第二个帧缓冲区对象,将其绑定到paintGL(),然后使用glBlitFramebuffer(以考虑多重采样)将内容与默认帧缓冲区交换以显示渲染,但使用第二个帧缓冲区从gl_FragData[1] 读取。但这感觉有点“讨厌”。

【问题讨论】:

    标签: qt opengl framebuffer rendertarget


    【解决方案1】:

    我想向QOpenGLWidget 的默认帧缓冲区添加第二个渲染目标。

    答案很简单,您不能将第二个颜色附件添加到任何 OpenGL 默认帧缓冲区对象。

    OpenGL 4.6 API Compatibility Profile Specification; 2.1. EXECUTION MODEL; page 9

    有两类帧缓冲区:当上下文成为当前上下文时,窗口系统提供的帧缓冲区与上下文相关联,以及应用程序创建的帧缓冲区。 窗口系统提供的帧缓冲区称为默认帧缓冲区。应用程序创建的帧缓冲区,称为帧缓冲区对象,可以根据需要创建。一个上下文可以与两个帧缓冲区相关联,一个用于读取和绘图操作中的每一个。默认帧缓冲区和帧缓冲区对象主要通过配置和管理其状态的接口来区分。

    GL 命令对默认帧缓冲区的影响最终由窗口系统控制,它分配帧缓冲区资源,决定 GL 可以在任何给定时间访问默认帧缓冲区的哪些部分,并将这些部分的结构传达给 GL。因此,没有用于初始化 GL 上下文或配置默认帧缓冲区的 GL 命令
    同样,GL 也没有解决在物理显示设备上显示帧缓冲区内容(包括通过伽马校正等技术转换单个帧缓冲区值)的问题。

    OpenGL 4.6 API Compatibility Profile Specification; 9.2. BINDING AND MANAGING FRAMEBUFFER OBJECTS; page 340

    Framebuffer 对象(具有非零名称的对象)在一些重要方面与默认帧缓冲区不同。首先,与默认的帧缓冲区不同,帧缓冲区对象对帧缓冲区中的每个逻辑缓冲区都有可修改的连接点。

    【讨论】:

    • 也许我的问题在术语方面有点误导。至少我说的是 QOpenGLWidget 的默认帧缓冲区,而不是整个窗口系统。对我来说,这听起来像是小部件创建了自己的帧缓冲区,它用于渲染内容,然后将其交换到主帧缓冲区。
    • 那么您认为小部件的默认缓冲区与窗口系统的默认缓冲区相同吗?抱歉,我不明白 ;) 如果不一样,我应该可以向它添加渲染目标,不是吗?
    • 啊,我明白了。感谢您的回答!
    【解决方案2】:

    对于挑选,您可以只渲染到单独的QOpenGLFramebufferObject,即:

    makeCurrent();
    glPushAttrib(GL_VIEWPORT_BIT);
    glViewport(0, 0, width(), height());
    QOpenGLFramebufferObject fbo(width(), height(), QOpenGLFramebufferObject::CombinedDepthStencil);
    fbo.bind();
    glClearColor(1, 1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    […] render stuff […]
    fbo.release();
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glPopAttrib();
    QImage fboImage(fbo.toImage());
    QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32);
    

    另请参阅 toImage docs 解释需要 2 个 QImages。

    【讨论】:

    • 这实际上也是我的解决方案(参见stackoverflow.com/questions/50964539/…)。我只是想知道是否可以直接将纹理附加到默认缓冲区以避免创建自定义帧缓冲区对象。不过谢谢你的回答!
    猜你喜欢
    • 2018-11-30
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多