Qt Creator 上提供了一些在 Qt Quick 程序中使用 OpenGL 的示例,本文主要参考示例 "fboitem"。搜索示例 "fbo",有两个 QQuickFramebufferObject 相关的 demo,演示了如何运用 Qt 帧缓冲对象渲染 QML 小部件。
(之前学习这个 demo 时很多东西还没理解,现在把代码重新整理了下)
1.知识点(主要翻译自 Qt 文档)
QQuickFramebufferObject 继承自 QQuickItem,该类型使得我们可以在帧缓冲对象(FBO)上渲染我们的小部件,Qt Quick SceneGraph 框架会将这个 FBO 渲染到屏幕上。要注意的是,该类仅在 Qt Quick 通过 OpenGL 渲染时才起作用。可以把 QQuickFramebufferObject 类当作是 OpenGL 版的 QQuickPaintedItem,其使用 QPainter 绘制,也是 QQuickItem 的子类。
在大多数平台上,渲染将在专用线程上进行。因此,QQuickFramebufferObject 类在 QML Item 实现和 FBO 呈现之间强制执行严格的分离。QML 所需的所有 Item 逻辑,例如属性和与 UI 相关的辅助函数,都应该位于 QQuickFramebufferObject 类的子类中。与渲染相关的所有内容都必须位于QQuickFramebufferObject::Renderer 类中。
为了避免 Item 和 Render 两个线程的读写竞争,应避免使用共享变量。Item 和 Render 之间的通信应该通过 QQuickFramebufferObject::renderer::synchronize() 函数进行。当 GUI 线程被阻塞时,将在渲染线程上调用此函数。或者使用队列连接的信号槽或者事件。
Renderer 和 FBO 对象都是 Qt 内部管理内存,不用我们主动释放。
要渲染到 FBO 中,我们应该继承 Renderer 类,并重新实现 Renderer::render() 函数(相当于 QOpenGLWidget 的 paintGL() 函数)。Renderer 子类实例是从 createRenderer() 返回的。
从 Qt5.4 开始,QQuickFramebufferObject 类是一个纹理提供者(texture provider),可以直接用于 ShaderEffects 和其他使用纹理提供者(texture provider)的类。
这里之前还遇到个问题,创建的 QOpenGLFramebufferObject 帧缓冲对象附加了深度缓冲,但是 render 的时候没清除深度缓冲,导致顶点没有被渲染出来。
2.代码实现GitHub项目链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20200128_FBO
(注意:我使用的Qt版本为5.12.6或5.15.2,编译器 MSVC2019 )
主要代码:
QQuickFramebufferObject 子类
#pragma ocne
#include
//QML UI 相关逻辑放到 QQuickFramebufferObject 子类
//渲染相关放到 QQuickFramebufferObject::Renderer 子类
//该类仅在 Qt Quick 通过 OpenGL 渲染时才起作用
class FBOItem : public QQuickFramebufferObject
{
Q_OBJECT
public:
FBOItem(QQuickItem *parent = nullptr);
//Renderer 实例是从 createRenderer() 返回的
QQuickFramebufferObject::Renderer *createRenderer() const override;
};
#include "FBOItem.h"
#include "FBORenderer.h"
#include "FBORenderer2.h"
FBOItem::FBOItem(QQuickItem *parent)
: QQuickFramebufferObject(parent)
{
//上下翻转,这样就和OpenGL的坐标系一致了
setMirrorVertically(true);
}
QQuickFramebufferObject::Renderer *FBOItem::createRenderer() const
{
//Renderer 和 FBO 都是内部管理的内存
return new FBORenderer();
}
QQuickFramebufferObject::Renderer 子类
#pragma once
#include
#include
#include
#include
//#include
#include
//渲染相关放到 QQuickFramebufferObject::Renderer 子类
class FBORenderer : public QQuickFramebufferObject::Renderer,
protected QOpenGLFunctions_3_3_Core
{
public:
FBORenderer();
//要渲染到 FBO,需要继承 Renderer 类并重新实现其 render() 函数
void render() override;
//创建新的 FBO 时调用,如 resize 时
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
private:
//着色器程序
QOpenGLShaderProgram program;
};
#include "FBORenderer.h"
#include
FBORenderer::FBORenderer()
{
//为当前上下文初始化OpenGL函数解析
initializeOpenGLFunctions();
//着色器代码
//in输入,out输出,uniform从cpu向gpu发送
const char *vertex_str=R"(#version 330 core
layout (location = 0) in vec3 vertices;
void main() {
gl_Position = vec4(vertices,1.0);
})";
const char *fragment_str=R"(#version 330 core
uniform vec3 myColor;
void main() {
gl_FragColor = vec4(myColor,1.0);
})";
//将source编译为指定类型的着色器,并添加到此着色器程序
if(!program.addCacheableShaderFromSourceCode(
QOpenGLShader::Vertex,vertex_str)){
qDebug()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?