问题
I'd like to add a second render target to the default framebuffer of a QOpenGLWidget.
The reason is that I'd like to implement object picking and check whether the user hit an object by rendering a segmentation mask into gl_FragData[1]
. Unfortunately, you can only retrieve the GLuint
handle from the widget and there is no constructor of QOpenGLFramebufferObject
that takes in the handle and there is no other option to retrieve the framebuffer.
Is there any possibility to attach another texture to the default frame buffer of the widget without workarounds?
The only two options I can think of are:
1.
Attaching a texture using native OpenGL calls (I'd rather stick to pure Qt) like so in the initialization (of course I'll store segmentationTexture
to be able to delete it later):
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();
and then in paintGL()
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, buffers);
before the OpenGL draw calls and use glReadBuffer(GL_COLOR_ATTACHMENT1);
to retrieve the content from gl_FragData[1]
. Or maybe, if this doesn't work, using only native OpenGL code to generate the texture.
2.
Create a second framebuffer object, bind it in paintGL()
and then swap the content with the default framebuffer using glBlitFramebuffer
(to account for multisampling) to display the rendering, but use the second framebuffer to read from gl_FragData[1]
. But this feels a bit "nasty".
回答1:
I'd like to add a second render target to the default framebuffer of a
QOpenGLWidget
.
The answer is simple, you can't add a second color attachment, to any OpenGL default framebuffer object.
See OpenGL 4.6 API Compatibility Profile Specification; 2.1. EXECUTION MODEL; page 9
There are two classes of framebuffers: a window system-provided framebuffer associated with a context when the context is made current, and application-created framebuffers. The window system-provided framebuffer is referred to as the default framebuffer. Application-created framebuffers, referred to as framebuffer objects, may be created as desired, A context may be associated with two framebuffers, one for each of reading and drawing operations. The default framebuffer and framebuffer objects are distinguished primarily by the interfaces for configuring and managing their state.
The effects of GL commands on the default framebuffer are ultimately controlled by the window system, which allocates framebuffer resources, determines which portions of the default framebuffer the GL may access at any given time, and communicates to the GL how those portions are structured. Therefore, there are no GL commands to initialize a GL context or configure the default framebuffer.
Similarly, display of framebuffer contents on a physical display device (including the transformation of individual framebuffer values by such techniques as gamma correction) is not addressed by the GL.
See OpenGL 4.6 API Compatibility Profile Specification; 9.2. BINDING AND MANAGING FRAMEBUFFER OBJECTS; page 340
Framebuffer objects (those with a non-zero name) differ from the default framebuffer in a few important ways. First and foremost, unlike the default framebuffer, framebuffer objects have modifiable attachment points for each logical buffer in the framebuffer.
回答2:
For picking you can just render to a separate QOpenGLFramebufferObject
, i.e.:
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);
Also see the toImage docs explaining the need to for the 2 QImage
s.
来源:https://stackoverflow.com/questions/50943629/add-render-target-to-default-framebuffer-of-qopenglwidget