class QQuickRhiItem#

QQuickRhiItem 类是 QQuickFramebufferObject 的另一种便携式替代品,它不依赖于 OpenGL,而是允许通过 Qt Quick 与 QRhi API 集成渲染。 更多

Inheritance diagram of PySide6.QtQuick.QQuickRhiItem

新版本 6.7。

摘要#

属性#

方法#

虚函数#

信号#

备注

此文档可能包含自动从C++转换为Python的片段。我们始终欢迎对片段翻译的贡献。如果您发现翻译问题,您也可以通过在https:/bugreports.qt.io/projects/PYSIDE上创建票据来告知我们。

详细描述#

警告

本节包含自动从C++转换为Python的片段,可能包含错误。

备注

QQuickRhiItem在Qt 6.7中处于技术预览状态。API处于开发中,可能会发生变化。

QQuickRhiItem是Qt Quick世界中的QRhiWidget的对应物。这两个都可以被继承,它们都允许记录面向离屏颜色缓冲区的基于QRhi的渲染。然后,生成的2D图像与Qt Quick场景的其余部分进行合成。

备注

虽然 QQuickRhiItem 是一个公共的 Qt API,Qt Gui 模块中的 QRhi 类家族,包括 QShader 和 QShaderDescription,提供有限的兼容性保证。对于这些类没有源代码或二进制兼容性保证,这意味着 API 只保证与用于开发的 Qt 版本兼容。然而,为了将源代码不兼容的变更限制到最低,这些变更将仅在次要版本中(6.7、6.8 等等)进行。qquickrhiitem.h 并没有直接包含任何 QRhi 相关的头文件。当实现 QQuickRhiItem 的子类时,需要链接到 Qt::GuiPrivate(如果使用 CMake),并包含带有 rhi 前缀的相应头文件,例如 #include <rhi/qrhi.h>

QQuickRhiItem 是对传统 QQuickFramebufferObject 类的替代。后者本质上是与 OpenGL / OpenGL ES 相关,而 QQuickRhiItem 与 QRhi 类一起工作,允许使用 Vulkan、Metal、Direct 3D 11/12 和 OpenGL / OpenGL ES 运行相同的渲染代码。在概念上和功能上,它们非常相似,从 QQuickFramebufferObject 迁移到 QQuickRhiItem 是直接的。《QQuickFramebufferObject》 继续提供以确保与使用 OpenGL API 直接工作的现有应用程序代码兼容。

备注

当使用 Qt Quick 场景图的 software 适配时,QQuickRhiItem 将无法正常工作。

在大多数平台上,场景图渲染以及因此由QQuickRhiItem完成的渲染将在一个专用线程上执行。因此,QQuickRhiItem类严格执行了项目实现(QQuickItem子类)和实际渲染逻辑之间的分离。所有项目逻辑,例如暴露给QML的属性和UI相关辅助函数,都必须位于QQuickRhiItem子类中。所有与渲染相关的内容都必须位于QQuickRhiItemRenderer类中。为了避免来自两个线程的竞态条件和读写问题,确保渲染器和项目不要读写共享变量非常重要。项目与渲染器之间的通信应主要通过QQuickRhiItem::synchronize()函数进行。此函数将在渲染线程上调用,同时GUI线程被阻塞。对于项目与渲染器之间的通信,也可以使用入队连接或事件。

应用程序必须同时派生自QQuickRhiItemQQuickRhiItemRenderer。纯虚函数createRenderer()必须被重新实现,以返回一个QQuickRhiItemRenderer子类的新实例。

与QRhiWidget类似,QQuickRhiItem会自动管理颜色缓冲区,通常是一个二维纹理(QRhiTexture)或者当使用多采样时是一个QRhiRenderBuffer。(某些3D API在纹理和渲染缓冲区之间进行区分,而在其他某些API中,底层原生资源是相同的;渲染缓冲区主要用于允许OpenGL ES 3.0进行多采样)

默认情况下,纹理的大小将自适应于项目的大小(考虑了device pixel ratio)。如果项目大小改变,会将纹理重新创建为正确的尺寸。如果更喜欢固定大小,将fixedColorBufferWidthfixedColorBufferHeight设置为非零值。

QQuickRhiItem 是一个 纹理提供器,可以直接用于 ShaderEffects 以及其他使用纹理提供器的类。

虽然不是主要用途,QQuickRhiItem 还允许引入直接使用 3D 图形 API(如 Vulkan、Metal、Direct 3D 或 OpenGL)的渲染代码。有关在 QRhi 渲染过程中记录本地命令的详细信息,请参阅 QRhiCommandBuffer::beginExternal(),有关将现有本地纹理包装并随 QRhi 在后续渲染过程中使用的详细信息,请参阅 QRhiTexture::createFrom()。关于配置本地 3D API 环境(例如设备扩展)的信息也请见 QQuickGraphicsConfiguration,注意可以在足够早的时候通过调用 QWindow::setVulkanInstance() 将自定义 QVulkanInstance 与 QQuickWindow 相关联。

备注

QQuickRhiItem 总是使用与 QQuickWindow 相同的 QRhi 实例(以及更广泛的,相同的 OpenGL 上下文、Vulkan 设备等)。为了选择哪个底层 3D 图形 API 被使用,请在足够早的时候在 QQuickWindow 上调用 setGraphicsApi()。在场景图初始化后无法更改,并且场景中所有 QQuickRhiItem 实例都将使用相同的 3D API 进行渲染。

一个简单的示例

以下是一个 QQuickRhiItem 的子类的示例。以下是它的完整形式。它使用透视投影渲染一个三角形,三角形的旋转基于自定义项目的 angle 属性。(这意味着它可以被动画如来自 QML 的 NumberAnimation 驱动。)

class ExampleRhiItemRenderer(QQuickRhiItemRenderer):

# public
    def initialize(cb):
    def synchronize(item):
    def render(cb):
# private
    m_rhi = None
    std.unique_ptr<QRhiBuffer> m_vbuf
    std.unique_ptr<QRhiBuffer> m_ubuf
    std.unique_ptr<QRhiShaderResourceBindings> m_srb
    std.unique_ptr<QRhiGraphicsPipeline> m_pipeline
    m_viewProjection = QMatrix4x4()
    m_angle = 0.0f

class ExampleRhiItem(QQuickRhiItem):

    Q_OBJECT
    QML_NAMED_ELEMENT(ExampleRhiItem)
    Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged)
# public
    QQuickRhiItemRenderer createRenderer() override
    float angle() { return m_angle; }
    def setAngle(a):
# signals
    def angleChanged():
# private
    m_angle = 0.0f

QQuickRhiItemRenderer ExampleRhiItem.createRenderer()

    return ExampleRhiItemRenderer()

def setAngle(self, a):

    if m_angle == a:
        return
    m_angle = a
    angleChanged.emit()
    update()

def synchronize(self, rhiItem):

    item = ExampleRhiItem(rhiItem)
    if item.angle() != m_angle:
        m_angle = item.angle()

def getShader(name):

    f = QFile(name)
    return f.open(QIODevice.ReadOnly) if QShader.fromSerialized(f.readAll()) else QShader()

vertexData = {
    0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
    0.5f, -0.5f, 0.0f, 0.0f, 1.0f,

def initialize(self, cb):

    if m_rhi != rhi():
        m_pipeline.reset()
        m_rhi = rhi()

    if not 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(":/shaders/color.vert.qsb") },
            { QRhiShaderStage.Fragment, getShader(":/shaders/color.frag.qsb") }
        })
        inputLayout = QRhiVertexInputLayout()
        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()
        resourceUpdates = m_rhi.nextResourceUpdateBatch()
        resourceUpdates.uploadStaticBuffer(m_vbuf.get(), vertexData)
        cb.resourceUpdate(resourceUpdates)

    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)

def render(self, cb):

    resourceUpdates = m_rhi.nextResourceUpdateBatch()
    modelViewProjection = m_viewProjection
    modelViewProjection.rotate(m_angle, 0, 1, 0)
    resourceUpdates.updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData())
    clearColor = QColor.fromRgbF(0.4f, 0.7f, 0.0f, 1.0f)
    cb.beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates)
    cb.setGraphicsPipeline(m_pipeline.get())
    outputSize = renderTarget().pixelSize()
    cb.setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()))
    cb.setShaderResources()
    QRhiCommandBuffer.VertexInput vbufBinding(m_vbuf.get(), 0)
    cb.setVertexInput(0, 1, vbufBinding)
    cb.draw(3)
    cb.endPass()

值得注意的是,这个简单的类几乎与 QRhiWidget 介绍中所示的代码完全相同。顶点和片元着色器的代码与那里显示的相同。

一旦将我们的自定义项目公开给 QML(注意 QML_NAMED_ELEMENT),我们就可以在任何场景中实例化它。(在 CMake 项目中导入适当指定的为 qt_add_qml_module 的 URI 之后)

ExampleRhiItem {
    anchors.fill: parent
    anchors.margins: 10
    NumberAnimation on angle { from: 0; to: 360: duration: 5000; loops: Animation.Infinite }
}

有关更复杂的示例,请参阅 场景图 - RHI 纹理项目

另见

QQuickRhiItemRenderer 场景图 - RHI纹理项 场景图和渲染

class TextureFormat#

备注

可以在使用 from __feature__ import true_property 时直接使用属性,否则通过访问函数使用。

property alphaBlending: bool#

控制是否在绘制使用 QQuickRhiItem 和其渲染器生成的内容纹理的矩形时始终启用混合。

默认值是 false。这是出于性能考虑:如果没有半透明效果,因为 QQuickRhiItemRenderer 清除到不透明颜色,并且永远不会渲染 alpha 值小于 1 的片段,那么启用混合就没有意义。

如果 QQuickRhiItemRenderer 子类绘制时涉及半透明,则将此属性设置为 true。

备注

在特定情况下,即使此属性的值为 false,也会执行混合。例如,如果项的 opacity(更确切地说,从父级链继承的合成不透明度)小于 1,即使此属性设置为 false,也会自动启用混合。

备注

Qt Quick 场景图依赖于并期望预乘 alpha。例如,如果要在渲染器中将背景清除到 alpha 值为 0.5,则务必将红色、绿色和蓝色清除颜色值乘以 0.5。否则,混合结果将是不正确的。

访问函数
property colorBufferFormat: QQuickRhiItem.TextureFormat#

此属性控制用作颜色缓冲区的纹理的纹理格式。默认值是 TextureFormat::RGBA8。 QQuickRhiItem 仅支持渲染到 QRhiTexture 支持的格式子集。仅应指定 QRhi::isTextureFormatSupported() 报告为支持的格式,否则渲染将无法正常工作。

备注

当项及其渲染器已经被初始化并渲染完毕时,设置新的格式意味着由渲染器创建的所有 QRhiGraphicsPipeline 对象可能变得不可用,如果关联的 QRhiRenderPassDescriptor 现在由于不同的纹理格式而失效。类似于动态改变 sampleCount,这意味着 initialize() 或 render() 的实现必须注意释放现有的管路并创建新的。

访问函数
属性 effectiveColorBufferSize: QSize#

此属性暴露了底层颜色缓冲区(QRhiTexture 或 QRhiRenderBuffer)的尺寸(以像素为单位)。它在 GUI(主)线程上提供使用,用于 QML 绑定或 JavaScript。

备注

QQuickRhiItemRenderer 实现不应使用此属性。它们应该查询 render target 的大小。

备注

从主线程的角度来看,值异步可用,即当渲染线程发生渲染时值发生变化。这意味着此属性主要用于 QML 绑定。应用代码不应假设当 QQuickRhiItem 对象被构造时值已经是最新的。

这是一个只读属性。

访问函数
属性 fixedColorBufferHeight: int#

这项关联纹理的固定高度(以像素为单位)。当需要一个不依赖于项大小的固定纹理大小时,与此相关。此大小对项的几何形状没有影响(其大小和场景中的位置),这意味着纹理的内容将拉伸(放大)或缩小到项的区域上。

例如,将大小设置为项的大小(像素)的两倍,相当于执行了 2 倍的超采样(以两倍分辨率渲染,然后在纹理 quad 时隐式缩放)。

默认值为 0。值为 0 意味着纹理的大小遵循项大小。(纹理大小 = 项大小 * 设备像素比率)。

访问函数
属性 fixedColorBufferWidth: int#

项目中关联的纹理或渲染缓冲区的固定宽度,单位为像素。当需要固定的颜色缓冲区大小,而不依赖于项目大小时适用。这个大小对项目(其在场景中的大小和位置)的几何形状没有影响,这意味着纹理的内容将在项目区域上拉伸(放大)或缩小。

例如,将大小设置为项的大小(像素)的两倍,相当于执行了 2 倍的超采样(以两倍分辨率渲染,然后在纹理 quad 时隐式缩放)。

默认值为 0。值为 0 意味着纹理的大小遵循项大小。(纹理大小 = 项大小 * 设备像素比率)。

访问函数
属性 mirrorVertically: bool#

该属性控制绘制纹理四边形时是否翻转纹理UV。它对离屏颜色缓冲区的内容以及由QQuickRhiItemRenderer 实现的渲染没有影响。

默认值是 false

访问函数
属性 sampleCount: int#

该属性控制多采样抗锯齿的样本计数。默认值是 1,表示关闭MSAA。

有效值是 1、4、8,有时是 16 和 32。可以使用 QRhi::supportedSampleCounts() 在运行时查询支持的样本计数,但通常应用程序应请求 1(无MSAA)、4x(普通MSAA)或 8x(高MSAA)。

备注

设置新值意味着渲染器创建的 QRhiGraphicsPipeline 对象必须从那时起使用相同的样本计数。使用不同样本计数创建的现有 QRhiGraphicsPipeline 对象不再可以使用。当值发生变化时,所有颜色和深度-模板缓冲区将自动销毁和重新创建,并且再次调用 initialize()。然而,当 isAutoRenderTargetEnabled()false 时,管理此内容(与深度-模板缓冲区或额外的颜色缓冲区相关)将由应用程序负责。

将样本计数从默认的1更改为更高的值意味着 colorTexture() 变为 None,而 msaaColorBuffer() 开始返回一个有效的对象。切换回1(或0)意味着相反:在下一次调用initialize()时,msaaColorBuffer()将返回 None,而colorTexture()将再次变回有效。此外,只要样本计数大于1(即使用MSAA),resolveTexture() 返回一个有效的(非多采样)QRhiTexture。

访问函数
__init__([parent=None])#
参数:

parentQQuickItem

用给定的 parent 构造一个新的 QQuickRhiItem。

alphaBlending()#
返回类型:

bool

属性 alphaBlendingᅟ 的获取器。

alphaBlendingChanged()#

属性 alphaBlendingᅟ 的通知信号。

autoRenderTargetChanged()#
colorBufferFormat()#
返回类型:

TextureFormat

属性 colorBufferFormatᅟ 的获取器。

colorBufferFormatChanged()#

属性 colorBufferFormatᅟ 的通知信号。

摘要 createRenderer()#
返回类型:

QQuickRhiItemRenderer

重写此函数以创建并返回一个 QQuickRhiItemRenderer 子类的实例。

此函数将在渲染线程上调用,同时GUI线程被阻塞。

effectiveColorBufferSize()#
返回类型:

QSize

属性 effectiveColorBufferSizeᅟ 的获取器。

effectiveColorBufferSizeChanged()#

属性 effectiveColorBufferSizeᅟ 改变的通知信号。

fixedColorBufferHeight()#
返回类型:

int

属性 fixedColorBufferHeightᅟ 的获取器。

fixedColorBufferHeightChanged()#

属性 fixedColorBufferHeightᅟ 改变的通知信号。

fixedColorBufferWidth()#
返回类型:

int

属性 fixedColorBufferWidthᅟ 的获取器。

fixedColorBufferWidthChanged()#

属性 fixedColorBufferWidthᅟ 改变的通知信号。

isAutoRenderTargetEnabled()#
返回类型:

bool

返回当前自动深度-模板缓冲区和渲染目标管理设置。

默认情况下此值为 true

isMirrorVerticallyEnabled()#
返回类型:

bool

属性 mirrorVerticallyᅟ 的获取器。

mirrorVerticallyChanged()#

属性 mirrorVerticallyᅟ 的通知信号。

sampleCount()#
返回类型:

int

属性 sampleCountᅟ 的获取器。

sampleCountChanged()#

属性 sampleCountᅟ 的通知信号。

setAlphaBlending(enable)#
参数:

enable – bool

属性 alphaBlendingᅟ 的设置器。

setAutoRenderTarget(enabled)#
参数:

enabled – bool

控制项是否自动创建和维持深度-模板 QRhiRenderBuffer 和 QRhiTextureRenderTarget。默认值是 true。例如,从派生类的构造函数中尽早调用此函数,并将 enabled 设置为 false 以禁用此功能。

在自动模式下,深度-模板缓冲区的大小和样本计数遵循颜色缓冲纹理的设置。在非自动模式下,renderTarget() 和 depthStencilBuffer() 总是返回 None,此时初始化() 函数的实现取决于应用程序,以负责设置和管理这些对象。

setColorBufferFormat(format)#
参数:

formatTextureFormat

属性 colorBufferFormatᅟ 的设置器。

setFixedColorBufferHeight(height)#
参数:

height – int

属性 fixedColorBufferHeightᅟ 的设置器。

setFixedColorBufferWidth(width)#
参数:

width – int

属性 fixedColorBufferWidthᅟ 的设置器。

setMirrorVertically(enable)#
参数:

enable – bool

设置属性 mirrorVertically属性 的值。

setSampleCount(samples)#
参数:

samples – int

另见

sampleCount()

设置属性 sampleCount属性 的值。