QSGRenderNode Class
QSGRenderNode 类表示一组针对场景图使用的图形 API 的自定义渲染命令。更多
Header: | #include <QSGRenderNode> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS Quick) target_link_libraries(mytarget PRIVATE Qt6::Quick) |
qmake: | QT += quick |
继承: | QSGNode |
公共类型
enum | RenderingFlag { BoundedRectRendering, DepthAwareRendering, OpaqueRendering, NoExternalRendering } |
flags | RenderingFlags |
enum | StateFlag { DepthState, StencilState, ScissorState, ColorState, BlendState, …, RenderTargetState } |
flags | StateFlags |
公共函数
virtual | ~QSGRenderNode() override |
virtual QSGRenderNode::StateFlags | changedStates() const |
const QSGClipNode * | clipList() const |
(since 6.6) QRhiCommandBuffer * | commandBuffer() const |
virtual QSGRenderNode::RenderingFlags | flags() const |
qreal | inheritedOpacity() const |
const QMatrix4x4 * | matrix() const |
(since 6.0) virtual void | prepare() |
(since 6.5) const QMatrix4x4 * | projectionMatrix() const |
virtual QRectF | rect() const |
virtual void | releaseResources() |
virtual void | render(const QSGRenderNode::RenderState *state) = 0 |
(since 6.6) QRhiRenderTarget * | renderTarget() const |
详细说明
QSGRenderNode 允许创建场景图节点,这些节点可通过QRhi (Qt 6.6 以来的常用方法)、直接通过 3D 图形 API(如 OpenGL、Vulkan 或 Metal)或在使用software
后端时通过QPainter 执行自己的自定义渲染。
QSGRenderNode 是将自定义 2D/3D 渲染集成到Qt Quick 场景的三种方法之一。另外两种方法是在Qt Quick 场景中执行渲染before
或after
,或者针对专用渲染目标(纹理)生成一个独立的渲染通道,然后让场景中的一个项目显示纹理。基于 QSGRenderNode 的方法与前者类似,不涉及额外的渲染传递或渲染目标,并允许在Qt Quick 场景自身渲染的 "内联 "注入自定义渲染命令。
另请参阅 场景图 - 自定义 QSGRenderNode。
成员类型文档
枚举 QSGRenderNode::RenderingFlag
flags QSGRenderNode::RenderingFlags
从flags() 返回的位掩码的可能值。
常量 | 值 | 说明 |
---|---|---|
QSGRenderNode::BoundedRectRendering | 0x01 | 表示render() 的实现不会在rect() 以项坐标报告的区域之外进行渲染。根据场景图后端,这样的节点实现可以提高渲染效率。例如,当场景中的所有渲染节点都设置了此标记时,software 后端可以继续使用更优化的部分更新路径。 |
QSGRenderNode::DepthAwareRendering | 0x02 | 表示render() 的实现符合场景图的预期,即只在场景坐标中生成一个 Z 值为 0 的节点,然后通过从 RenderState::projectionMatrix() 和matrix() 中获取的矩阵进行转换,如render() 的注释所述。根据场景图后端不同,这种节点实现可以提高渲染效率。例如,当场景中的所有渲染节点都设置了此标记时,批处理 OpenGL 渲染器可以继续使用更优化的路径。 |
QSGRenderNode::OpaqueRendering | 0x04 | 表示render() 的实现为rect() 报告的整个区域写出不透明像素。默认情况下,渲染器必须假定render() 也能输出半透明或全透明像素。在某些情况下,设置此标志可以提高性能。 |
QSGRenderNode::NoExternalRendering | 0x08 | 表示prepare() 和render() 的实现使用了QRhi 系列 API,而不是直接调用 OpenGL、Vulkan 或 Metal 等 3D API。 |
RenderingFlags 类型是QFlags<RenderingFlag> 的类型定义。它存储 RenderingFlag 值的 OR 组合。
另请参见 render()、prepare()、rect() 和QRhi 。
枚举 QSGRenderNode::StateFlag
flags QSGRenderNode::StateFlags
该枚举是一个位掩码,用于标识几种状态。
常量 | 值 | 描述 |
---|---|---|
QSGRenderNode::DepthState | 0x01 | 深度 |
QSGRenderNode::StencilState | 0x02 | 模板 |
QSGRenderNode::ScissorState | 0x04 | 剪刀 |
QSGRenderNode::ColorState | 0x08 | 颜色 |
QSGRenderNode::BlendState | 0x10 | 混合色 |
QSGRenderNode::CullState | 0x20 | 库尔 |
QSGRenderNode::ViewportState | 0x40 | 查看图片 |
QSGRenderNode::RenderTargetState | 0x80 | 渲染目标 |
StateFlags 类型是QFlags<StateFlag> 的类型定义。它存储了状态标志值的 OR 组合。
成员函数文档
[override virtual noexcept]
QSGRenderNode::~QSGRenderNode()
销毁呈现节点。派生类应执行类似于releaseResources() 的清理工作。
当使用底层图形 API 时,场景图将确保 CPU 端等待 GPU 完成提交给场景图图形命令队列的所有工作,然后再删除场景图节点。因此,除非render() 的实现使用了额外的命令队列,否则没有必要在此发出额外的等待。
对于QRhi 和资源(如QRhiBuffer,QRhiTexture,QRhiGraphicsPipeline 等),使用智能指针(如 std::unique_ptr)通常是很好的做法,这通常可以避免实现析构函数的需要,并使源代码更加紧凑。不过,请记住,实现releaseResources() 仍然很重要,这很可能会在 unique_ptrs 上发出大量 reset() 调用。
另请参见 releaseResources()。
[virtual]
QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
当底层渲染 API 为 OpenGL 时,该函数应返回一个掩码,其中每一位代表由render() 函数改变的图形状态:
常量 | 说明 |
---|---|
DepthState | 深度写入掩码、启用深度测试、深度比较函数 |
StencilState | 模板写入掩码、启用模板测试、模板操作、模板比较函数 |
ScissorState | 启用剪刀,启用剪刀测试 |
ColorState | 清除颜色、颜色写入掩码 |
BlendState | 启用混合、混合功能 |
CullState | 启用正面、剔除面 |
ViewportState | 视口 |
RenderTargetState | 渲染目标 |
对于 OpenGL 以外的 API,唯一相关的值是与命令列表/缓冲区中记录的动态状态变化相对应的值。例如,D3D11 中的 RSSetViewports、RSSetScissorRects、OMSetBlendState、OMSetDepthStencilState,或 Vulkan 中的 vkCmdSetViewport、vkCmdSetScissor、vkCmdSetBlendConstants、vkCmdSetStencilRef,而且只有当这些命令被添加到通过 QSGRendererInterface 查询到的场景图命令列表中时才会出现::CommandList 资源枚举。在管道状态对象中设置的状态无需在此报告。同样,与绘制调用相关的设置(管道状态、描述符集、顶点或索引缓冲区绑定、根签名、描述符堆等)总是由场景图重新设置,因此render() 可以自由更改它们。
RenderTargetState 目前,Vulkan 等应用程序接口已不再支持 "Scenegraph"。这是自然规律。() 被调用时, 场景图的主命令缓冲区正在记录一个渲染通道,因此不可能更改目标并启动另一个渲染通道(至少在该命令缓冲区)。因此,返回 设置的值是不合理的。render Qt Quick RenderTargetState
该函数由呈现器调用,以便在呈现该节点后重置状态。这使得render() 的实现更加简单,因为它无需查询和还原这些状态。
默认实现返回 0,表示render() 中没有更改相关状态。
注: 此函数可在render() 之前调用。
注意: 在 Qt XML 6 和基于QRhi 的渲染中,唯一相关的值是ViewportState 和ScissorState 。其他值可以返回,但在实际应用中会被忽略。
const QSGClipNode *QSGRenderNode::clipList() const
返回当前剪辑列表。
[since 6.6]
QRhiCommandBuffer *QSGRenderNode::commandBuffer() const
返回当前的命令缓冲区。
此函数在 Qt 6.6 中引入。
另请参阅 renderTarget()。
[virtual]
QSGRenderNode::RenderingFlags QSGRenderNode::flags() const
返回描述此呈现节点行为的标志。
默认实现返回 0。
另请参阅 RenderingFlag 和rect()。
qreal QSGRenderNode::inheritedOpacity() const
返回当前的有效不透明度。
const QMatrix4x4 *QSGRenderNode::matrix() const
返回当前模型视图矩阵的指针。
[virtual, since 6.0]
void QSGRenderNode::prepare()
在帧准备阶段调用。每次调用render() 之前都会调用该函数。
与render() 不同,该函数会在场景图开始在底层命令缓冲区记录当前帧的渲染传递之前调用。这在使用 Vulkan 等图形应用程序接口进行渲染时非常有用,因为在这些应用程序接口中,需要在渲染传递之前记录复制类型的操作。
默认实现为空。
在实现使用QRhi 渲染的QSGRenderNode 时,可通过QQuickWindow::rhi() 从QQuickWindow 查询QRhi 对象。要获取用于提交工作的QRhiCommandBuffer ,请调用commandBuffer() 。要查询活动呈现目标的信息,请调用renderTarget() 。详情请参阅{Scene Graph - Custom QSGRenderNode}示例。
此函数在 Qt 6.0 中引入。
[since 6.5]
const QMatrix4x4 *QSGRenderNode::projectionMatrix() const
返回当前投影矩阵的指针。
在render() 中,该矩阵与 RenderState::projectionMatrix() 返回的矩阵相同。该获取器的存在是为了让prepare() 也能查询投影矩阵。
在使用现代图形 API 或 Qt XML 自身的图形抽象层时,人们很可能希望将*projectionMatrix() * *matrix()
加载到统一缓冲区中。但这需要在prepare() 中完成,因此不在渲染传递的记录范围内。这就是为什么在prepare() 和render() 中可以直接从QSGRenderNode 中查询这两个矩阵的原因。
该函数在 Qt 6.5 中引入。
[virtual]
QRectF QSGRenderNode::rect() const
返回render() 所触及区域的项目坐标矩形边界。该值仅在flags() 包括BoundedRectRendering 时使用,否则将被忽略。
结合BoundedRectRendering 报告矩形对于software
后端尤为重要,否则场景中的呈现节点将触发全屏更新,从而跳过所有部分更新优化。
对于覆盖相应QQuickItem 整个区域的呈现节点,返回值将为(0, 0, item->width(), item->height())。
注: 由于场景图节点不受QQuickItem 几何图形的限制,因此节点也可以在项目宽度和高度指定的边界之外自由渲染,只要此函数正确报告即可。
另请参阅 flags().
[virtual]
void QSGRenderNode::releaseResources()
当需要立即释放该节点分配的所有自定义图形资源时,将调用此函数。如果节点没有通过正在使用的图形 API 直接分配图形资源(缓冲区、纹理、渲染目标、栅栏等),则无需在此做任何操作。
如果不释放所有自定义资源,在某些系统上会导致图形设备丢失情况下的不正确行为,因为图形系统的后续重新初始化可能会失败。
注意: 某些场景图后端可能选择不调用此函数。因此,预计QSGRenderNode 实现会在析构函数和 releaseResources() 中执行清理。
与析构函数不同的是,在调用 releaseResources() 之后调用render() 时,预计它可以重新初始化所需的所有资源。
对于 OpenGL,调用析构函数和该函数时,场景图的 OpenGL 上下文都是当前的。
[pure virtual]
void QSGRenderNode::render(const QSGRenderNode::RenderState *state)
该函数由渲染器调用,应使用当前使用的图形 API(OpenGL、Direct3D 等)直接调用命令来绘制该节点。
有效不透明度可通过inheritedOpacity() 获取。
投影矩阵可通过state 获取,而模型视图矩阵可通过matrix() 获取。组合矩阵就是投影矩阵乘以模型视图矩阵。投影矩阵可确保场景中项目的正确堆叠。
使用所提供的矩阵时,顶点数据的坐标系遵循通常的QQuickItem 约定:左上角为 (0,0),右下角为相应QQuickItem 的宽度()和高度()减一。例如,假设每个顶点的坐标布局为两个浮点(x-y),那么一个覆盖半个项目的三角形可按逆时针方向指定为(宽-1,高-1)、(0,0)、(0,高-1)。
注: QSGRenderNode 是实现自定义 2D 或 2.5DQt Quick 项目的一种方法。它并非用于将真正的 3D 内容集成到Qt Quick 场景中。QQuickFramebufferObject,QQuickWindow::beforeRendering() 或 OpenGL 以外的 API 的相应功能可以更好地支持这种使用情况。
注: QSGRenderNode 的性能明显优于基于纹理的方法(如QQuickFramebufferObject ),尤其是在片段处理能力有限的系统上。这是因为它避免了渲染到纹理后再绘制纹理四边形。相反,QSGRenderNode 允许记录绘制调用,与场景图的其他命令保持一致,避免了额外的渲染目标和可能昂贵的纹理和混合。
剪切信息会在调用函数前计算出来。希望将剪切考虑在内的程序可以根据state 中的信息设置剪切或模版。模版缓冲区中会填充必要的剪辑形状,但模版测试是否启用取决于实现。
有些场景图后端,特别是软件,不使用剪刀或模板。在这些软件中,剪辑区域是作为普通的QRegion 提供的。
在实现使用QRhi 渲染的QSGRenderNode 时,可通过QQuickWindow::rhi() 从QQuickWindow 查询QRhi 对象。要获取用于提交工作的QRhiCommandBuffer ,请调用commandBuffer() 。要查询活动呈现目标的信息,请调用renderTarget() 。详情请参阅{Scene Graph - Custom QSGRenderNode}示例。
使用 Qt 6 及其基于QRhi 的场景图渲染器,调用此函数时,即使正在使用 OpenGL,也不应假设活动(OpenGL)状态。调用此函数时,对命令列表/缓冲区上绑定的流水线和动态状态不做任何假设。
注意: 应禁用深度写入。启用深度写入可能会导致意想不到的结果,这取决于所使用的场景图后端和场景中的内容,因此请谨慎使用。
注意: 在 Qt XML 6 中,changedStates() 的用途有限。更多信息,请参阅changedStates() 文档。
对于某些图形 API,包括直接使用QRhi 时,可能还需要重新实现prepare() 或连接到QQuickWindow::beforeRendering() 信号。在命令缓冲区记录渲染过程的开始(Vulkan 时为 vkCmdBeginRenderPass,Metal 时为通过 MTLRenderCommandEncoder 开始编码)之前,会调用/发送这些信号。使用此类 API 时,无法在 render() 内进行记录复制操作。相反,应在prepare() 或连接到 beforeRendering(使用 DirectConnection)的插槽中进行此类操作。
另请参见 QSGRendererInterface 和QQuickWindow::rendererInterface()。
[since 6.6]
QRhiRenderTarget *QSGRenderNode::renderTarget() const
返回当前的呈现目标。
提供此功能主要是为了使prepare() 和render() 的实现能够使用QRhi 访问QRhiRenderTarget 的renderPassDescriptor 或pixel size 。
要构建QRhiGraphicsPipeline (这意味着必须提供QRhiRenderPassDescriptor ),请从呈现目标中查询 renderPassDescriptor。不过,请注意,在自定义QQuickItem 和QSGRenderNode 的生命周期内,呈现目标可能会发生变化。例如,考虑一下在项目或其祖先上动态设置layer.enabled: true
时会发生什么:这会触发呈现到纹理中,而不是直接呈现到窗口中,这意味着QSGRenderNode 从此将使用不同的呈现目标。新的呈现目标可能具有不同的像素格式,这可能会导致已构建的图形管道不兼容。这可以通过以下逻辑来处理:
if (m_pipeline && renderTarget()->renderPassDescriptor()->serializedFormat() != m_renderPassFormat) { delete m_pipeline; m_pipeline = nullptr; } if (!m_pipeline) { // Build a new QRhiGraphicsPipeline. // ... // Store the serialized format for fast and simple comparisons later on. m_renderPassFormat = renderTarget()->renderPassDescriptor()->serializedFormat(); }
此函数在 Qt 6.6 中引入。
另请参阅 commandBuffer()。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.