关于opengl:使用QOpenGLTexture和QOpenGLFramebufferObject渲染TO和WITH纹理

Render TO and WITH texture using QOpenGLTexture and QOpenGLFramebufferObject

根据Qt5中QOpenGLTexture的文档,可以渲染WITH纹理,也可以渲染TO纹理。关于这两种用法,是否有任何简单的示例?
可以在此链接中找到这种用法的场景。下面列出了与此有关的有问题的代码:

在屏幕外部分:

屏幕外渲染的初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
p_offscreen_context_ = std::make_unique<QOpenGLContext>();
p_offscreen_context_->setFormat(_p_onscreen_context->format()); // _p_onscreen_context is the context in the onscreen rendering part
p_offscreen_context_->setShareContext(_p_onscreen_context);
if (!p_offscreen_context_->create()) {
    std::cerr <<"Failed to create OpenGL context!!" << std::endl;
    return;
}
p_offscreen_surface_ = std::make_unique<QOffscreenSurface>();
p_offscreen_surface_->setFormat(p_offscreen_context_->format());
p_offscreen_surface_->create();
if (!p_offscreen_surface_->isValid()) {
    std::cerr <<"Failed to create Offscreen Surface!!" << std::endl;
    return;
}
make_current(); // p_offscreen_context_->makeCurrent(p_offscreen_surface_.get());
p_functions_ = std::make_unique<QOpenGLFunctions>();
p_functions_->initializeOpenGLFunctions();
create_frame_buffer_object(); // see below
done_current(); // p_offscreen_context_->doneCurrent();

在功能create_frame_buffer_object()中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
make_current();
if (p_frame_buffer_object_) { p_frame_buffer_object_->release(); }
QOpenGLFramebufferObjectFormat format;
format.setSamples(0);
p_frame_buffer_object_ =
    std::make_shared<QOpenGLFramebufferObject>(width_, height_, format); // width_ and height_ represent the size of buffer
if (!p_frame_buffer_object_->isValid()) {
  std::cerr <<"Failed to create Frame Buffer Object!!" << std::endl;
  return;
}
p_frame_buffer_object_->bind();
p_functions_->glClear(
    GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
p_frame_buffer_object_->release();
done_current();

执行渲染:

1
2
3
4
5
6
7
8
std::lock_guard<std::mutex> lock_guard(mutex_);
make_current();
if (!initialized_.exchange(true)) { initiate_opengl(); } // do some initilization in the renderer part, see below
p_frame_buffer_object_->bind();
paint_opengl(); // do the rendering in the renderer part
texture_unit_ = p_frame_buffer_object_->texture(); // record the texture unit used in the FBO
p_frame_buffer_object_->release();
done_current();

屏幕部分:

这部分仅涉及渲染器的初始化和渲染。没什么。

渲染器部分(由屏幕上和屏幕外部分使用):

初始化:

1
2
3
4
// creations of vertex array object, vertex index buffer and other resources are omitted

// creation of the QOpenGLTexture (might be wrong, but don't know how to fix)
p_texture_ = std::make_shared<QOpenGLTexture>(image.mirrored()); // image is a QImage which has the same width and height as FBO

执行渲染:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Render image via shader
p_program_->bind(); // shaders have been successfully compiled
{
    p_vertex_array_object_->bind();
    bind_texture(); // for offscreen part: p_texture_->bind();
                    // for onscreen part: p_texture_->bind(unit_);
                    // unit_ is the value of texture_unit_ from offscreen part
    ::glDrawElements(GL_TRIANGLE_FAN,
                     static_cast<GLsizei>(vertex_indices_.size()),
                     GL_UNSIGNED_SHORT,
                     static_cast<void *>(0)); // actually draw a quad
    release_texture(); // for offscreen part: p_texture_->release();
                       // for onscreen part: p_texture_->release(unit_);
    p_vertex_array_object_->release();
}
p_program_->release();

我对QOpenGLTextureQOpenGLFramebufferObject的机制不太熟悉,因此任何修复我的错误并向我展示该机制的人都将不胜感激。


纹理本身只是一块内存,一个缓冲区。您可以根据需要在该内存中读写。大多数情况下,像素着色器从中读取纹理。这就是您描述的从纹理渲染的内容。

渲染到纹理要有趣得多。此处的想法是创建动态的纹理:它以您指定的方式随时间变化。因此,首先,对帧缓冲区对象中的每种颜色执行一次初始渲染过程,然后使用其他渲染过程将第一遍的结果用作纹理。这将渲染为纹理。该技术打开了一个有趣的动态效果的全新世界。

对于这种效果的简单示例,David Wolf的OpenGL着色语言食谱第4章中的render-to-tex示例非常好。我在下面粘贴了此示例的图像结果。您可以在Wolf的github存储库中找到该示例的源代码。

在第一遍中将茶壶渲染到FBO,然后在第二遍中将其应用于多维数据集。

对不起,这不是QT特有的,但从我的阅读看来,本例中两者之间的术语看起来非常相似。我无法诊断出与此有关的任何特定问题,但希望我能帮助给出一个很好的示例,以从纹理渲染/从纹理渲染。