涉及2D内容的Qt Quick 3D场景

3D世界中的2D元素

Qt Quick 3D提供高效创建和渲染结合3D和2D元素的场景。

我们所说的结合3D-2D场景是指什么?

根据其本质,一个代表2D场景中3D视口的View3D对象可以很容易地与Qt Quick项结合,例如,矩形、图片、文本等,围绕、在下面或在上面放置在View3D项周围,而View3D项本身也是一个Qt Quick Item

考虑以下示例

import QtQuick
import QtQuick3D

Rectangle {
    gradient: Gradient {
        GradientStop { position: 0; color: "steelblue" }
        GradientStop { position: 1; color: "black" }
    }
    Text {
        text: "Hello 2D World"
        font.pointSize: 32
        color: "red"
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
    }
    Item {
        width: 400; height: 400
        anchors.centerIn: parent
        View3D {
            anchors.fill: parent
            environment: SceneEnvironment { backgroundMode: SceneEnvironment.Color; clearColor: "lightGray" }
            PerspectiveCamera { z: 600 }
            DirectionalLight { }
            Model {
                source: "#Cube"
                materials: PrincipledMaterial { baseColor: "green"; metalness: 0.0; roughness: 0.0 }
                eulerRotation: Qt.vector3d(30, 45, 0)
            }
        }
    }
}

在这里,3D场景是灰色背景的区域。窗口的其余部分由2D Qt Quick项组成。这些项可以与View3D重叠,但不属于3D世界,不使用3D坐标系,也不参与3D场景的变换。

如果我们想在3D世界中添加2D项并让它们真正地参与所有3D变换,该怎么办?例如,我们能否在3D世界中放置RectangleText项,使它们跟随立方体的旋转,并且始终放置在其上方?

在接下来的部分中,我们将探讨如何实现这一点。虽然示例使用RectangleText,但任何Qt Quick内容,包括Qt Quick控件、ShapeShaderEffectParticleSystem都可以如此使用。

注意:也存在其他方法可用来整合2D内容与3D对象。向3D节点添加2D项允许在3D世界中自由组合2D和3D对象,但不会允许在3D对象表面上渲染2D内容。如果目标是用Qt Quick生成的内容纹理化3D网格,请使用TexturesourceItem属性。

用作纹理图的Qt Quick内容3D场景中的Qt Quick项

将2D项添加到3D节点

关键因素是Object3D接受Item子对象并按特殊方式处理的能力。Object3DNode类型的基类。这意味着任何Node以及Model等类型都可以接受Item子对象。

从Qt 6.0开始,将二维项添加到三维节点不再触发将二维内容渲染为OpenGL纹理、Vulkan图像或类似内容。相反,默认模式是将二维项与三维场景中的其他内容一起行内渲染,在同一个渲染通道中。二维项应用了所有的三维转换。这些转换从包装的节点继承。

import QtQuick
import QtQuick3D

Rectangle {
    gradient: Gradient {
        GradientStop { position: 0; color: "steelblue" }
        GradientStop { position: 1; color: "black" }
    }
    Text {
        text: "Hello 2D World"
        font.pointSize: 32
        color: "red"
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
    }
    Item {
        width: 400; height: 400
        anchors.centerIn: parent
        View3D {
            anchors.fill: parent
            environment: SceneEnvironment { backgroundMode: SceneEnvironment.Color; clearColor: "lightGray" }
            PerspectiveCamera { z: 600 }
            DirectionalLight { }
            Model {
                Node {
                    y: 150
                    Rectangle {
                        anchors.horizontalCenter: parent.horizontalCenter
                        color: "white"
                        width: text3d.width
                        height: text3d.height
                        Text {
                            id: text3d
                            text: "Hello 3D World"
                            font.pointSize: 32
                        }
                    }
                }
                source: "#Cube"
                materials: PrincipledMaterial { baseColor: "green"; metalness: 0.0; roughness: 0.0 }
                eulerRotation: Qt.vector3d(30, 45, 0)
            }
        }
    }
}

与第一个代码段相比,模型节点现在有一个子节点,该节点通过转换将其放置在立方体位置的上方。`150` 是相对立方体中心的值,在三维坐标空间中。

Model {
    Node {
        y: 150

然后是 矩形 项。当将其添加到 节点 下方时,三维和二维世界的边界会在内部交叉,但这对于应用程序设计者来说是透明的。会自动生成一个不可见的 内容项,允许矩形引用 父节点 并执行锚定。节点的三维转换应用于整个二维子树。在示例中,这意味着旋转将与立方体的旋转相匹配。

Node {
    y: 150
    Rectangle {
        anchors.horizontalCenter: parent.horizontalCenter

二维和三维中的坐标系

二维项继续使用Qt Quick的坐标系:Y轴从上到下运行,单位对应于像素。另一方面,三维节点使用三维坐标系:Y轴向上指,单位对应于厘米,并受相机的透视投影影响。

默认情况下,顶级项的左上角放置在节点的原点处。这意味着二维子树中的顶级项通常会希望指定一个锚点,例如 anchors.centerIn: parent,或者,如在示例中一样,将水平中心锚定到父节点的水平中心,从而在三维节点上水平居中二维内容。

进一步考虑事项

  • 虽然二维项目会与三维对象一起行内渲染,但它们不参与光照,也不会投射阴影。
  • 裁剪 可能不会像预期那样表现,应避免使用。如果裁剪对二维项目的布局至关重要,应用程序应明确回退到将内容渲染到纹理。这可以通过向3D节点下的顶级 `Item` 添加 `layer.enabled: true` 来实现。
  • 从Qt 6.2开始,按需将输入传递给二维项。来自指定位器的输入必须发生在线性声明的项的 `childrenRect` 内。
  • 虽然将二维项树添加到三维场景相对便宜,但应该避免在三维场景内放置过多的二维子树(数百个或更多),因为这可能会增加内存和图形资源的使用。请注意,这指的是在三维节点下的分离子树的数量,而不是那个子树中的二维项目总数。例如,上面的QML片段中只有一个二维子树。

另请参阅Qt Quick 3D - Quick Items示例QQuickItem::mapFromGlobal

© 2024 Qt公司有限責任公司。本文件所述文档贡献是各自拥有者的版权。本文件的文档根据自由软件基金会发布的 GNU自由文档许可版1.3 许可条款提供。Qt及其相关徽标是芬兰和/或其他国家的世界各地的Qt公司有限責任公司的商标。所有其他商标均为各自拥有者的财产。