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

news2024/11/16 17:27:17

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 主题!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

重学java 52.Collections集合工具类、泛型

"我已不在地坛&#xff0c;地坛在我" —— 《想念地坛》 24.5.28 一、Collections集合工具类 1.概述:集合工具类 2.特点: a.构造私有 b.方法都是静态的 3.使用:类名直接调用 4.方法: static <T> boolean addAll(collection<? super T>c,T... el…

学习笔记——IP地址网络协议——网络掩码(Netmask)

三、网络掩码(Netmask) 1、网络掩码概述 网络掩码(Netmask)又称子网掩码(Subnet Mask)网络掩码为32 bit&#xff0c;与IP地址的位数一样&#xff0c;通常也以点分十进制数来表示。 子网掩码不能单独存在&#xff0c;它必须结合IP地址一起使用。子网掩码只有一个作用&#xf…

SpringBoot 单元测试 指定 环境

如上图所示&#xff0c;在配置窗口中添加--spring.profiles.activedev&#xff0c;就可以了。

创建采购订单免费行项目,注意事项

1.我在使用bapi&#xff08;BAPI_PO_CREATE1&#xff09;创建采购订单免费行项目的时候&#xff0c;还是报错了请输入净价格。 解决方式&#xff1a;把这些数据都赋值好&#xff0c;那么你的采购订单行项目就是免费项目。 BAPIMEPOITEM-IR_IND 空 &#xff08;发票收据标识&am…

【C语言】文件操作(终卷)

前言 我们在上一卷中了解了顺序读写的函数&#xff0c;现在就让我们从随机读写的函数开始吧。 什么是随机读写&#xff1f; 就是想在哪个位置读或写都行&#xff0c;比较自由。文件打开时光标默认在起始位置。想从后面的某个部分读或写&#xff0c;就得让文件指针来到那个位…

Linux系统Docker部署Apache Superset并实现远程访问详细流程

目录 前言 1. 使用Docker部署Apache Superset 1.1 第一步安装docker 、docker compose 1.2 克隆superset代码到本地并使用docker compose启动 2. 安装cpolar内网穿透&#xff0c;实现公网访问 3. 设置固定连接公网地址 前言 作者简介&#xff1a; 懒大王敲代码&#xff0…

【小工具】电磨机

BUSCH DREMEL3000 博世 琢美 技术规范

儿童护眼灯什么牌子好点?五款儿童护眼灯品牌推荐

儿童护眼灯什么牌子好点&#xff1f;根据往年的统计&#xff0c;我国青少年近视率位居世界第一&#xff0c;儿童青少年总体近视率达到了52.7%。其中&#xff0c;6岁儿童的近视率为14.5%&#xff0c;小学生为36.0%&#xff0c;初中生为71.6%&#xff0c;高中生为81%。造成近视的…

事务与锁的顺序不对导致并发的问题

错误使用锁和事务导致并发 在事务中添加锁来解决并发的问题&#xff0c;这并没有解决并发的问题。 Transactional Override public void execute(){try {lock.lock()// 开启锁// 查询出数据mapper.select();// 根据查询出数据计算并写入到数据库中mapper.udpate()} finally {…

Java 中的 Map 集合:入门篇

在 Java 编程中&#xff0c;Map 是用于存储键值对。它提供了快速的查找和检索功能&#xff0c;是处理大量数据的理想选择。 本文将深入介绍 Java 中的 Map 集合&#xff0c;包括其基本概念、常见实现类、典型用法以及一些常见问题的解决方案。 1. Map 的基本概念 Map 是一种键…

#01 Stable Diffusion基础入门:了解AI图像生成

文章目录 前言什么是Stable Diffusion?Stable Diffusion的工作原理如何使用Stable Diffusion?Stable Diffusion的应用场景结论 前言 在当今迅速发展的人工智能领域&#xff0c;AI图像生成技术以其独特的魅力吸引了广泛的关注。Stable Diffusion作为其中的一项前沿技术&#…

2. keepalived结合LVS配合使用

keepalived结合LVS配合使用 1、后端nfs存储提供项目文件2、后端nfs上集中安装MySQL&#xff0c;共用数据库3、业务服务器通过LNMP正常部署wordpress博客&#xff0c;客户端通过DNS解析可正常访问4、所有业务服务器上修改arp参数、配置VIP5、配置keepalived实现LVS高可用5.1 kee…

【大学物理】期末复习双语笔记

3 vectors and scalar 20 damped harmonic motion,forced harmonic motion, superposition of SHM damped harmonic motion underdamped motion:欠阻尼 critical damped零界阻尼 over damped过阻尼 energy of damped harmonic motion application of damped oscillation:减震器…

Python的super方法两种调用方式解析

Python由于具有多继承的特点&#xff0c;因此在使用super()方法的时候&#xff0c;需要考虑调用的是哪个父类的方法&#xff0c;这里面涉及到以下内容&#xff1a; 菱形继承(钻石集成)MRO&#xff08;method resolution order&#xff09; 下面的图像就是菱形继承。 抛开复…

Spring 中如何控制 Bean 的加载顺序?

如果你脱口而出说添加 Order 注解或者是实现 Ordered 接口&#xff0c;那么恭喜&#xff0c;你掉坑了。 一 Order 注解和 Ordered 接口 在 Spring 框架中&#xff0c;Order 是一个非常实用的元注解&#xff0c;它位于 spring-core 包下&#xff0c;主要用于控制某些特定上下文…

va_start和va_end使用介绍

一 概述 采用C语言编程的时候&#xff0c;函数中形式参数的数目通常是确定的&#xff0c;在调用时要依次给出与形式参数对应的所有实际参数。但在某些情况下希望函数的参数个数可以根据需要确定。典型的例子有大家熟悉的函数printf()、scanf()和系统调用execl()等。那么它们是怎…

【Docker】学习笔记(超万字图文整理)

前言 再此感谢黑马程序员提供的Docker课程&#xff01; 什么是Docker&#xff1f;看这一篇干货文章就够了&#xff01; UPD: 补充更新微服务集群、Docker镜像仓库部分内容 所有笔记、生活分享首发于个人博客 想要获得最佳的阅读体验&#xff08;无广告且清爽&#xff09;&#…

ai写作神器app有哪些?好用的智能写作APP推荐

ai写作神器app有哪些&#xff1f;AI写作神器app在现代写作领域正迅速崭露头角&#xff0c;它们不仅极大提升了创作效率&#xff0c;而且通过集成前沿的人工智能技术&#xff0c;为创作者们提供了前所未有的便利。这些app能够智能分析写作需求&#xff0c;快速生成高质量的内容&…

PMP(项目管理)- PMBOK第七版重点解析

PMP&#xff08;项目管理&#xff09;- PMBOK第七版重点解析 本文内容是PMBOK第七版的重点章节精华提炼 参考资料内容&#xff1a;PMBOK第七版&PRINCE2第七版 参考资料在文末获取&#xff0c;关注我&#xff0c;分享优质前沿资料&#xff08;IT、运维、编码、互联网…&a…

边缘计算的AI小板——OrangePi AI Pro

简介 OrangePi AI Pro是一款基于Allwinner H6处理器的嵌入式AI计算设备&#xff0c;适用于物联网和边缘计算。它具有强大的性能、低功耗、多接口和小尺寸。 本文分为三个部分&#xff1a; 一、对该板进行简单的开箱介绍。 二、 将SD卡中的系统迁移到由于该板支持SD卡、SSD…