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

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

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

相关文章

一次 K8s 故障诊断:从 CPU 高负载到存储挂载泄露根源揭示

一、背景 现代软件部署中,容器技术已成为不可或缺的一环,在云计算和微服务架构中发挥着核心作用。随着容器化应用的普及,确保容器环境的可靠性成为了一个至关重要的任务。这就是容器SRE(Site Reliability Engineering&#xff0c…

【学习笔记】Windows GDI绘图(十)Graphics详解(中)

文章目录 Graphics的方法AddMetafileComment添加注释BeginContainer和EndContainer新建、还原图形容器不指定指定源与目标矩形指定源与目标矩形 Clear清空并填充指定颜色CopyFromScreen截图CopyPixelOperation DrawImage绘制图像DrawImage的GraphicsDrawImageAbort回调ExcludeC…

初识 peerDependencies

目录 初步认识 peerDependencies semver 介绍 # 摘要 # 简介 # 语义化版本控制规范(SemVer) # 合法语义化版本的巴科斯范式语法 # 为什么要使用语义化的版本控制? # FAQ 示例讲解:vue-router 插件 # 说明 声明 验证 初…

在Windows11系统上搭建SFTP服务器

利用OpenSSH搭建SFTP服务器 下载安装部署OpenSSH创建一个测试账户测试链接为SFTP用户配置根目录下载安装部署OpenSSH 参考链接 部署完启动服务要使用管理员模式。 net start sshd创建一个测试账户 使用PC的微软账户是访问不了SFTP的。 需要使用被微软账户覆盖掉的系统账户和…

如何解决段转储问题

非常恶心 ,这个问题困了我一个月,怀疑过代码有问题 ,怀疑过数据集没处理好,怀疑过环境没有配置好,尝试改动,跑过很多次,还是段转储报错卡住。。。 然后一个月荒废,打算放弃这个模型…

【SQL查询优化】关联与聚合操作战实——从多值标签中提取水果名称

需求概述 目标是查询特定call_id关联的label_cd中代码所对应的水果名称,期望输出格式为:call_id对应的结果为水果->苹果, 水果->香蕉。 pg数据库 原始数据结构 items表:存储调用ID及包含多个代码的标签。 INSERT INTO "items&q…

8086 汇编笔记(九):call 指令 和 ret 指令

一、ret 和 retf ret 用栈中的数据,修改IP的内容,从而实现近转移; retf 指令用栈中的数据,修改CS和IP的内容,从而实现远转移。 CPU执行ret指令时,进行下面两步操作: (1&#xff0…

微信自定义小程序源码系统 众多组件随心搭 各行各业都适用的小程序 带完整的安装代码包以及搭建教程

系统概述 微信自定义小程序源码系统是一款基于微信官方开发框架进行深度定制的源码系统。该系统整合了众多优质组件,通过可视化的拖拽式操作,让开发者无需编写复杂的代码,即可快速搭建出符合自己需求的小程序。同时,该系统支持多…

iTerm2 携手 OpenAI,带来命令行的自然语言革新

在技术不断进步的今天,命令行工具的智能化已成为提升效率的关键。iTerm2,macOS 系统上广受欢迎的开源终端工具,通过最新版本 v3.5 的发布,实现了与 OpenAI 的集成,引领了这一变革。 iTerm2 简介 iTerm2 是一款功能强…

为什么选择mobx

对于React而言,大家熟能而详的是redux,但我们的项目用的是mobx,接下来就让我给你详细说下它的优势和不足,可以参考。 MobX是什么? MobX 是一种简单易用的状态管理库,它采用基于观察者的模式,可…

qcom 平台系统签名流程

security boot 平台的东东,oem 可定制的功能有限,只能参考平台文档,可以在高通的网站上搜索:Secure Boot Enablement,然后找对应平台的文档xxx-Secure Boot Enablement User Guide, step by step 操作即可 开机校验流…

django支持https

测试环境,可以用django自带的证书 安装模块 sudo pip3 install django_sslserver服务端https启动 python3 manage.py runsslserver 127.0.0.1:8001https访问 https://127.0.0.1:8001/quota/api/XXX

CodeBlocks官方主题颜色更换及方法

文章目录 一、前言二 、用工具导入配置文件2.1 运行 cb_share_config.exe文件2.2 替换文件2.3 设置主题 三、配置主题3.1 步骤13.2 步骤23.3 步骤3 四、设置光标4.1 配置字体4.2 展示 行号 五、设置左边行号区域部分六、设置完后的效果七、下载地址 一、前言 Codeblocks 默认的…

【Python系列】Python装饰器

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【数据结构】图论中求最短路径——迪杰斯特拉算法(Dijkstra)、弗洛伊德算法(Floyd)

目录 最短路径 (*)迪杰斯特拉算法(Dijkstra)迪杰斯特拉算法(Dijkstra)的算法原理: 弗洛伊德算法(Floyd)弗洛伊德算法(Floyd)的算法原理:弗洛伊德算法的&#…

哪种价格行为指标对投资者有用?AnzoCapital昂首资本总结6个特征

各位投资者都知道价格行为指标对于交易极具助益,无论是初学者还是专业交易员都能运用。构建外汇交易系统时,这类指标堪称核心且必不可少的工具。 但不是所有的价格行为指标都对投资者有用的,哪种价格行为指标才是对投资者有用的,都…

CogVLM2多模态开源大模型部署与使用

CogVLM2多模态开源大模型部署与使用 项目简介 CogVLM2 是由清华大学团队发布的新一代开源模型系列。2024年5月24日,发布了Int4版本模型,只需16GB显存即可进行推理。2024年5月20日,发布了基于llama3-8b的CogVLM2,性能与GPT-4V相当…

论文AI率过高?掌握这四种技巧轻松降重

随着人工智能技术的突飞猛进,AI生成内容(AIGC)已被广泛用于学术论文撰写中,提高效率同时也带来了原创性的挑战。面对日益严格的学术审查,一个突出的问题是:使用AI代写的论文能否通过内容检测?因…

Linux 搭建 ZeroTier 的 Moon 服务器

系统:centos 7.6 轻量云服务器:腾讯云 Moon是什么,为什么需要Moon? ZeroTier通过自己的多个根服务器帮助我们建立虚拟的局域网,让虚拟局域网内的各台设备可以打洞直连。这些根服务器的功能有些类似于通过域名查询找到…

Spark 中dtypes函数

前言 在Spark SQL中,dtypes函数用于获取DataFrame或Dataset中各列的数据类型信息。它返回一个由列名和数据类型组成的元组列表,其中每个元组表示一列的名称和相应的数据类型。 在Spark SQL中使用dtypes函数的示例代码: # 导入必要的库 from …