「Qt Widget中文示例指南」如何实现一个简单的RHI小部件示例(二)

Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。

本文将为大家演示如何使用QRhi、Qt的3D API和着色语言抽象层渲染三角形。

点击获取Qt Widget组件下载(Q技术交流:166830288)

「Qt Widget中文示例指南」如何实现一个快捷编辑器

在很多方面,这个示例都是QWidget世界中的RHI窗口示例的对应。这个应用程序中的QRhiWidget子类使用带有基本顶点和片段着色器的简单图形管道渲染单个三角形。与普通的基于QWindow的应用程序不同,本示例不需要担心较低级别的细节,比如设置窗口和QRhi,或者处理交换链和窗口事件,因为这些都由这里的QWidget框架负责。QRhiWidget子类的实例被添加到QVBoxLayout中,为了使示例保持最小和紧凑,没有引入更多的小部件或3D内容。

在上文中(点击这里回顾>>),我们为大家介绍了结构和main(),本文将继续介绍如何完成渲染!

渲染设置

在examplewidget.cpp中,小部件实现使用一个辅助函数从.qsb文件加载一个QShader对象,这个应用程序通过Qt资源系统将预置的.qsb文件嵌入到可执行文件中。由于模块依赖(并且由于仍然支持qmake),本例不使用方便的CMake函数qt_add_shaders(),而是随.qsb文件一起作为源代码树的一部分。我们鼓励现实世界的应用程序避免这种情况,而是使用Qt Shader Tools模块的CMake集成功能(qt_add_shaders)。不管采用哪种方法,在c++代码中,绑定/生成的.qsb文件的加载是相同的。

static QShader getShader(const QString &name)
{
QFile f(name);
return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
}

让我们看一下initialize()的实现,首先查询和存储QRhi对象以供以后使用,并允许在以后调用该函数时进行比较。当存在不匹配时(例如,当小部件在窗口之间移动时),需要重新创建图形资源的重建,是通过销毁和清空一个合适的对象来触发的。在这种情况下是m_pipeline。该示例没有主动演示窗口之间的修复,它还准备好处理在调整窗口大小时可能发生的小部件大小变化。这不需要特殊的处理,因为initialize()每次发生时都被调用,因此查询renderTarget()->pixelSize()或colorTexture()->pixelSize()总是给出最新的、最新的像素大小。这个例子没有准备好改变纹理格式和多样本设置,因为它只使用默认值(RGBA8和没有多样本抗锯齿)。

void ExampleRhiWidget::initialize(QRhiCommandBuffer *cb)
{
if (m_rhi != rhi()) {
m_pipeline.reset();
m_rhi = rhi();
}

当需要(重新)创建图形资源时,initialize()使用非常典型的基于qrhi的代码来完成此工作。具有交错位置颜色顶点数据的单个顶点缓冲区就足够了,而模型视图投影矩阵则通过64字节(16个浮点数)的统一缓冲区公开。统一缓冲区是唯一的着色器可见资源,它只在顶点着色器中使用。图形管道依赖于很多默认值(例如,关闭深度测试、禁用混合、启用颜色写入、禁用面部剔除、三角形的默认拓扑等)顶点数据布局是x, y, r, g, b,因此步幅是5个浮点数,而第二个顶点输入属性(颜色)有2个浮点数的偏移量(跳过x和y)。每个图形管道必须与一个QRhiRenderPassDescriptor相关联,这可以从基类管理的QRhiRenderTarget中检索。

注意:这个例子依赖于QRhiWidget的默认autoRenderTarget设置为true,这就是为什么它不需要管理渲染目标,而可以通过调用renderTarget()来查询现有的渲染目标。

if (!m_pipeline) {
m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
m_vbuf->create();

m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
m_ubuf->create();

m_srb.reset(m_rhi->newShaderResourceBindings());
m_srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()),
});
m_srb->create();

m_pipeline.reset(m_rhi->newGraphicsPipeline());
m_pipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/shader_assets/color.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/shader_assets/color.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
m_pipeline->setVertexInputLayout(inputLayout);
m_pipeline->setShaderResourceBindings(m_srb.get());
m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
m_pipeline->create();

QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
cb->resourceUpdate(resourceUpdates);
}

最后,计算投影矩阵。这取决于小部件的大小,因此在每次函数调用中都无条件地完成。

注意:投影矩阵包括来自QRhi的校正矩阵,以适应归一化设备坐标的3D API差异。(例如,Y向下 vs. Y向上)

应用-4的平移只是为了确保z值为0的三角形是可见的。

const QSize outputSize = renderTarget()->pixelSize();
m_viewProjection = m_rhi->clipSpaceCorrMatrix();
m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_viewProjection.translate(0, 0, -4);
}
渲染

小部件记录单个呈现传递,其中包含单个绘制调用。

在初始化步骤中计算的视图投影矩阵与模型矩阵相结合,在这种情况下,模型矩阵恰好是一个简单的旋转,然后将得到的矩阵写入统一缓冲区。注意resourceUpdates是如何传递给beginPass()的,这是一个不必手动调用resourceUpdate()的快捷方式。

void ExampleRhiWidget::render(QRhiCommandBuffer *cb)
{
QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
m_rotation += 1.0f;
QMatrix4x4 modelViewProjection = m_viewProjection;
modelViewProjection.rotate(m_rotation, 0, 1, 0);
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());

在渲染通道中,记录一个带有3个顶点的绘制调用。在初始化步骤中创建的图形管道绑定在命令缓冲区上,并且将视口设置为覆盖整个小部件。为了使统一缓冲区对(顶点)着色器可见,setShaderResources()调用时不带参数,这意味着使用m_srb,因为它在管道创建时与管道相关联。在更复杂的渲染器中,传入不同的QRhiShaderResourceBindings对象并不罕见,只要该对象与管道创建时给出的布局兼容即可。没有索引缓冲区,只有一个顶点缓冲区绑定(vbufBinding中的单个元素引用创建管道时指定的QRhiVertexInputLayout的绑定列表中的单个条目)。

const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f);
cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates);

cb->setGraphicsPipeline(m_pipeline.get());
const QSize outputSize = renderTarget()->pixelSize();
cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(3);

cb->endPass();

一旦记录了渲染通道,就会调用update()。这将请求一个新的框架,并用于确保小部件不断更新,并且三角形看起来是旋转的。默认情况下,呈现线程(在本例中为主线程)由呈现速率限制。在这个例子中没有适当的动画系统,所以旋转将在每一帧中增加,这意味着三角形将以不同的刷新率以不同的速度旋转。

update();
}
Qt Widget组件推荐
  • QtitanRibbon - Ribbon UI组件:是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件,QtitanRibbon致力于为Windows、Linux和Mac OS X提供功能完整的Ribbon组件。
  • QtitanChart - Qt类图表组件:是一个C ++库,代表一组控件,这些控件使您可以快速地为应用程序提供漂亮而丰富的图表。
  • QtitanDataGrid - Qt网格组件:提供了一套完整的标准 QTableView 函数和传统组件无法实现的独特功能。使您能够将不同来源的各类数据加载到一个快速、灵活且功能强大的可编辑网格中,支持排序、分组、报告、创建带状列、拖放按钮和许多其他方便的功能。
  • QtitanDocking:允许您像 Visual Studio 一样为您的伟大应用程序配备可停靠面板和可停靠工具栏。黑色、白色、蓝色调色板完全支持 Visual Studio 2019 主题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/692153.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里大模型又又又又开源了!这次还是王炸产品!

阿里大模型又双叒叕开源了:刚刚,Qwen2 宣布开源! 不到一年时间,阿里云通义千问先后开源近 10 款不同尺寸的大语言模型,之前开源的 Qwen 系列 72B、110B 模型就曾多次登顶 HuggingFace 的 Open LLM Leaderboard 开源模型…

两个不同的TA Instance之间可以共享全局变量吗

答案:不能。 在GP规范里其实是有规定,在不同的TA Instance之间,都是有着各自的physical memory space的,都是相互独立物理地址空间的。 不同的TA instance之间,各自拥有各自的堆空间、可写全局数据段、可写静态数据段。…

Python可视化 | 使用matplotlib绘制面积图示例

面积图是数据可视化中的一个有效工具,用于说明时间上的关系和趋势。它们提供了一种全面的、视觉上迷人的方法,通过熟练地将折线图的可读性与填充区域的吸引力相结合来呈现数值数据。 在本文中,我们将学习更多关于在Python中创建面积折线图的…

前端渲染大量数据思路【虚拟列表】【异步机制】

当浏览器遇到性能瓶颈导致页面卡顿时,你会怎么处理?如何查找问题的原因? 浏览器本身自带性能检测工具,通常我们分析由脚本导致的页面卡顿会选择 性能(performance) 选项卡,在其中我们可以找到导…

从诺曼底登陆八十周年说起

昨天(2024年6月6日)是诺曼底登陆(Normandy Campaign)八十周年纪念日。媒体上有很多对相关纪念活动的报道。 诺曼底登陆战役,是第二次世界大战也是世界战争史上规模最大的登陆战役。敦刻尔克大撤退后,西欧大…

Qt Window Dialog 无标题栏 ,无边框,可拖动

1.效果: 2. 主要实现步骤: 设置窗口 flag: this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); 创建变量存储位置 QPoint m_dragPosition; 对鼠标左键按下和移动事件做处理 void DraggableDialog::mousePre…

【Linux操作系统】Linux中进程的五种状态:R、S、D、T、X以及僵尸进程、孤儿进程

操作系统中有许多同时执行的进程,这些进程都可能处于不同的状态代表着不同的含义。 R运行状态(running) 概念:并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。 我们运行可执行程序myproc利用指令 ps ajx可以看到进程…

Java 18 新功能概述

Java 18 在 2022 年 3 月 22 日正式发布,Java 18 不是一个长期支持版本。 包含多项新特性和改进,如文件系统链接、文本块、表达式求值API、ForkJoinPool优化、Optional新方法等。 亮点还包括预览特性:Record Pattern Matching for Switch和增…

Elastic Search(ES)Java 入门实操(3)数据同步

基本概念和数据查询代码: Elastic Search (ES)Java 入门实操(1)下载安装、概念-CSDN博客 Elastic Search(ES)Java 入门实操(2)搜索代码-CSDN博客 想要使用 ES 来查询数…

为什么会有虚像

本来我就打算写虚像相关的内容,实际上我看不懂光学的内容,我只是发觉书上没有使用变分法来做,而只是解析几何的变换,这个做法完全脱离实际,物理书为什么会这样写不知道原因,但是很明显这样的内容也非常的复…

操作系统复习-存储管理之段页式存储管理

存储管理之段页式存储管理 页式存储管理(等分划分) 字块是相对物理设备的定义页面则是相对逻辑空间的定义指的都是大小一样的一块内存页式存储管理是将进程逻辑空间等分成若干大小的页面相应的把物理内存空间分成与页面大小的物理块以页面为单位把进程空间装进物理内存中分散的…

【MySQL】常见可执行程序

本文使用的版本是MySQL8,5.7可能会有所不同。 MySQL提供了一些重要的程序用来管理和操作数据库。这里会介绍一些常用的程序及其使用。对于MySQL程序的使用,可以查看官方帮助手册来学习。 MySQL :: MySQL 8.0 Reference Manual :: 6 MySQL Programs 程序…

normalizing flows vs 直方图规定化

normalizing flows名字的由来 The base density P ( z ) P(z) P(z) is usually defined as a multivariate standard normal (i.e., with mean zero and identity covariance). Hence, the effect of each subsequent inverse layer is to gradually move or “flow” the da…

C# Maui 报错:程序“[15748] MauiApp1.exe”已退出,返回值为 2147942405 (0x80070005)

“MauiApp1.exe”(CoreCLR: DefaultDomain): 已加载“C:\Program Files\dotnet\shared\ Microsoft.NETCore.App\8.0.6\System.Private.CoreLib.dll”。 “MauiApp1.exe”(CoreCLR: clrhost): 已加载“E:\cDemo\MauiApp1\MauiApp1\bin\Debug\net8.0-windows10.0.19041.0\win10-x…

数智融通 创新发展|亚信科技携AntDB、Data OS与隐私计算产品,赋能企业高质量发展

5月21日,亚信科技在云端举办了一场别开生面的研讨会——“数智融通 创新发展”,聚焦企业数智化升级的前沿话题。资深产品经理和技术架构师们面对面深入交流,分享创新成果与实战案例,共同探索企业数智化转型的新路径。 图1&#xf…

重构某测试站点

一、计算校验值 校验值结果: 文件名称:培训用centos.rar,文件大小:1,335,759,953,MD5:534EC38CDA7DA2196C84AC8F6092514B,SHA1:FD35D86A27A007AE10872980C48653A110DF6067&#xf…

【Ardiuno】ESP32单片机初试点亮LED小灯

之前用的Ardiuno的主板做过一些简单的开发实验,按照相关说明还是很容易进行操作的。最近看了ESP32可以有wifi的功能,也就买来实验一下。 ESP32的主板开发环境安装,按照说明的安装下载程序总是报错,又上网搜索半天最后按照CSDN上某…

算法006:查找总价格为目标值的两个商品

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/ 题干说的很复杂,简化一…

IDEA使用阿里通义灵码插件

在这个AI火热的时代,纯手工写代码已经有点out了,使用AI插件可以帮我们快速写代码,起码能省去写那些简单、重复性的代码,大大提高编码效率,在这里我推荐使用阿里的通义灵码 注册安装 安装注册好后,打开我们…

前端技术探索:从基础到进阶

前端技术作为现代Web开发中不可或缺的一部分,其重要性不言而喻。随着技术的快速发展,前端领域涌现出了许多经典且值得深入探索的技术和框架。本文将带您领略前端技术的魅力,从基础到进阶,一起探讨前端开发的精髓。 一、前端技术基…