提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
原创|使用教程|编辑:龚雪|2024-06-04 10:21:03.880|阅读 19 次
概述:本文将为大家介绍如何使用Qt Widget小部件如何实现一个简单的RHI小部件示例,欢迎下载最新版组件体验~
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
相关链接:
Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。
本文将为大家演示如何使用QRhi、Qt的3D API和着色语言抽象层渲染三角形。
Qt技术交流群:166830288 欢迎一起进群讨论
在很多方面,这个示例都是世界中的RHI窗口示例的对应。这个应用程序中的子类使用带有基本顶点和片段着色器的简单图形管道渲染单个三角形。与普通的基于的应用程序不同,本示例不需要担心较低级别的细节,比如设置窗口和QRhi,或者处理交换链和窗口事件,因为这些都由这里的QWidget框架负责。QRhiWidget子类的实例被添加到中,为了使示例保持最小和紧凑,没有引入更多的小部件或3D内容。
在上文中(点击这里回顾>>),我们为大家介绍了结构和main(),本文将继续介绍如何完成渲染!
在examplewidget.cpp中,小部件实现使用一个辅助函数从.qsb文件加载一个对象,这个应用程序通过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(); }
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@cahobeh.cn
文章转载自:慧都网本文将探讨如何使用 Spire.XLS for .NET 在 C# 程序中导入 Excel 数据到数据库以及导出数据库到 Excel 文件,实现数据在 Excel 和数据库之间无缝流转。
在本文中,我们将向您展示如何逐步执行此操作,告诉您什么是 SCORM,为什么需要使用它,并列出我们测试过的最佳 SCORM 转换工具之一——iSpring Suite。
本文主要介绍如何使用Kendo UI for Angular组件的ListView来构建带有图表的仪表板,欢迎下载新版控件体验!
在本文中,您将学习如何使用Spire.PDF for .NET在 C# 中向 PDF 文档添加页码。
一个跨平台的C++图形用户界面应用程序开发框架。
QtitanChart性能优异的跨平台Qt类图表组件
QtitanRibbon专业全面 & 实现Qt技术的跨平台Ribbon UI组件
QtitanDataGrid一个独特的Qt开发框架产品,吸收了Delphi、C++以及其他语言的优点
QtitanDocking一个用于允许创建类似于Microsoft可停靠用户界面的Qt框架组件。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@cahobeh.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢