您当前的位置: 首页 >  ui

龚建波

暂无认证

  • 4浏览

    0关注

    312博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Qt Quick OpenGL学习笔记:通过FBO帧缓冲绘制一个三角

龚建波 发布时间:2020-01-29 17:23:17 ,浏览量:4

0.前言

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()            
关注
打赏
1655829268
查看更多评论
0.0592s