具有自定义帧缓冲区和多个渲染目标的QOpenGLWidget

问题描述:

我的其他问题有关,我尝试渲染分割蒙版以启用对象拾取.但是我无法达到预期的效果.

Related to my other question, I'm trying to render a segmentation mask to enable object picking. But I am not able to achieve the desired result.

选项1根本不起作用.我无法检索颜色附件1的内容,也无法检查它是否存在(我仅使用本机OpenGL调用创建了附件).

Option 1 did not work at all. I was not able to retrieve the content of color attachment 1, or check if it existed at all (I created the attachment using only native OpenGL calls).

使用帖子,我能够通过创建带有第二个颜色附件的自定义帧缓冲区来绑定green.pngred.png图像,然后将其绑定并绘制到(全部在paintGL()中).

Using this post, I was able to reproduce the green.png and red.png images by creating a custom frame buffer with a second color attachment which is then bound and drawn to (all in paintGL()).

我不得不以某种方式使用该人的帧缓冲区创建代码,因为当我自己创建帧缓冲区时,总是会发出警告toImage called for missing color attachment,尽管我附加了颜色附件,并且在帧缓冲区上调用的textures()返回了两个对象.然后,我尝试在之后插入渲染代码

Somehow I had to use the person's frame buffer creation code because when I created the frame buffer myself there was always a warning saying toImage called for missing color attachment, although I attached the color attachment and textures() called on the frame buffer returned two objects. I then tried to insert my rendering code after

GLfloat red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
f->glClearBufferfv(GL_COLOR, 0, red);

GLfloat green[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
f->glClearBufferfv(GL_COLOR, 1, green);

但这仍然导致红色和绿色图像.但是,使用普通的默认帧缓冲区时,代码可以很好地呈现.我将着色器修改为(用于测试目的的简短版本):

but this still resulted in the red and green image. But the code renders fine when using the normal default framebuffer. I adapted the shader to (short version for testing purposes):

void main() {
       gl_FragData[0] = vec4(1.0, 1.0, 1.0, 1.0);
       gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0);
}

由于我能够产生红色和绿色图像,所以我假设必须有一种方法可以使用此自定义帧缓冲区检索碎片数据.我现在拥有的解决方案是该程序的完整副本(!)和另一个专用的片段着色器,其唯一目的是渲染分段,并第二次执行所有OpenGL绘制调用.您可能会猜到,尽管景色并不算大,而且我的计算机能够轻松处理,但这是一个难看的解决方案.有人有想法/链接吗?

Since I was able to produce the red and green image, I'm assuming there must be a way to retrieve the frag data with this custom framebuffer. The solution I have right now is a complete (!) copy of the program and another dedicated fragment shader which's sole purpose is to render the segmentation, and perform all OpenGL draw calls a second time. As you can guess, this is a somewhat ugly solution, although the scenery is not that large and my computer is able to handle it easily. Has anyone got an idea/link?

如果要在片段着色器,那么您必须声明多个输出变量:

If you want to write to multiple render targets in a Fragment shader, then you have to declare multiple output variables:

#version 330

layout(location = 0) out vec4 fragData0;
layout(location = 1) out vec4 fragData1;

void main() 
{
    fragData0 = vec4(1.0, 1.0, 1.0, 1.0);
    fragData1 = vec4(0.0, 0.0, 0.0, 1.0);
}

从GLSL 1.1版(#version 110,OpenGL 2.0)到GLSL 1.5版(#version 150,OpenGL 3.2),可以通过写入内置的片段着色器输出变量gl_FragData来实现相同的目的.

From GLSL version 1.1 (#version 110, OpenGL 2.0) to GLSL version 1.5 (#version 150, OpenGL 3.2), the same can be achieved by writing to the built in fragment shader output variable gl_FragData.

void main() 
{
    gl_FragData[0] = vec4(1.0, 1.0, 1.0, 1.0);
    gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0);
}

另请参见片段着色器输出-历代之久

要在Qt中使用多个渲染目标,必须在帧缓冲区中添加第二个颜色附件,并且必须由

To use multiple render targets in Qt, a 2nd color attachment has to be add to the framebuffer and the list of color buffers has to be specified by glDrawBuffers:

QOpenGLShaderProgram *program;
QOpenGLFramebufferObject *fb; 
int fb_width;
int fb_height,

fb = new QOpenGLFramebufferObject( fb_width, fb_height );
fb->addColorAttachment( fb_width, fb_height );

glViewport(0, 0, fb_width, fb_height);
fb->bind();
glClearColor(0, 0, 0, 1);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

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

program->bind();
// ..... do the drawing    

program->release();
fb->release();

可以访问附加到帧缓冲区的OpenGL纹理对象:

The OpenGL texture objects which are attached to the framebuffer, can be accessed:

QVector<GLuint> fb_textrues = fb->textures();