Render TO and WITH texture using QOpenGLTexture and QOpenGLFramebufferObject
根据Qt5中
可以在此链接中找到这种用法的场景。下面列出了与此有关的有问题的代码:
在屏幕外部分:
屏幕外渲染的初始化:
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(); |
在功能
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(); |
我对
纹理本身只是一块内存,一个缓冲区。您可以根据需要在该内存中读写。大多数情况下,像素着色器从中读取纹理。这就是您描述的从纹理渲染的内容。
渲染到纹理要有趣得多。此处的想法是创建动态的纹理:它以您指定的方式随时间变化。因此,首先,对帧缓冲区对象中的每种颜色执行一次初始渲染过程,然后使用其他渲染过程将第一遍的结果用作纹理。这将渲染为纹理。该技术打开了一个有趣的动态效果的全新世界。
对于这种效果的简单示例,David Wolf的OpenGL着色语言食谱第4章中的render-to-tex示例非常好。我在下面粘贴了此示例的图像结果。您可以在Wolf的github存储库中找到该示例的源代码。
在第一遍中将茶壶渲染到FBO,然后在第二遍中将其应用于多维数据集。
对不起,这不是QT特有的,但从我的阅读看来,本例中两者之间的术语看起来非常相似。我无法诊断出与此有关的任何特定问题,但希望我能帮助给出一个很好的示例,以从纹理渲染/从纹理渲染。