使用QOpenGLTexture和QOpenGLFramebufferObject

时间:2016-09-02 14:44:42

标签: opengl qt5 render-to-texture

根据Qt5中QOpenGLTexture的文档,可以渲染 WITH 纹理,还可以渲染 TO 纹理。有关这两种用法的简单例子吗? 这种用法的情景可以在this link找到。有关这方面的问题代码如下:

offscreen 部分:

屏幕外渲染的初始化:

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()中:

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();

进行渲染:

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();

onscreen 部分:

这部分只涉及渲染器的初始化和渲染。没别了。

渲染器部分(由 onscreen offscreen 部分使用):

初​​始化:

// 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

进行渲染:

// 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的机制不是很熟悉,所以任何修复错误并向我展示机制的人都会非常感激。

1 个答案:

答案 0 :(得分:1)

纹理本身只是一堆记忆,一种缓冲。您可以根据需要读取和写入此内存。通常,像素着色器正在读取纹理。这就是你所描述的从>纹理中渲染

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

对于这种效果的简单示例,David Wolf的OpenGL着色语言手册第4章中的render-to-tex示例非常好。我已经粘贴了下面这个例子的图像结果。您可以在Wolf's github repo for the book's examples上找到此示例的源代码。

The teapot is rendered to the FBO in the first pass, then applied to the cube in the second pass.

对不起,这不是QT特有的,但从我看来,看起来这两个例子之间的术语看起来非常相似。我无法诊断您遇到的任何具体问题,但希望我帮助提供了一个很好的渲染纹理的例子。