Qt Quick 包含 2D 内容的 3D 场景
三维世界中的二维项目
Qt Quick 3D 可高效创建和渲染结合了 3D 和 2D 元素的场景。
我们所说的 3D-2D 结合场景指的是什么?
从本质上讲,代表 2D 场景中 3D 视口的View3D 对象可以很容易地与Qt Quick 项目(如矩形、图像、文本)结合在一起,在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 场景是灰色背景区域。窗口的其余部分由二维Qt Quick 项组成。这些项目可以与View3D 重叠,但不是三维世界的一部分,不使用三维坐标系,也不参与三维场景的变换。
如果我们想在三维世界中加入二维项目,让它们真正参与所有三维变换,该怎么办?例如,我们能否在三维世界中放置Rectangle 和Text 物品,让它们跟随立方体旋转并始终位于立方体上方?
在下面的章节中,我们将探讨如何实现这一目标。虽然示例中使用的是Rectangle 和Text ,但任何Qt Quick 内容(包括Qt Quick Controls,Shape,ShaderEffect,ParticleSystem )都可以这样使用。
注: 还有其他方法可以将二维内容与三维对象整合在一起。将 2D 项目添加到 3D 节点可以在 3D 世界中自由组合 2D 和 3D 物体,但不能在 3D 物体表面渲染 2D 内容。如果要使用Qt Quick 生成的内容为 3D 网格绘制纹理,请使用Texture 的the sourceItem property 代替。
Qt Quick 用作纹理贴图的内容 | Qt Quick 三维场景中的项目 |
---|---|
将 2D 项目添加到 3D 节点
Object3D Item Object3D 是 类型的基类。这意味着任何 以及 等类型都可以接受 子类。Node Node Model Item
从 Qt 6.0 开始,向 3D 节点添加 2D 项目不再触发将 2D 内容渲染为 OpenGL 纹理、Vulkan 图像或类似内容。相反,默认模式是在同一渲染传递中将 2D 项与 3D 场景的其他内容一起渲染。2D 项目会应用所有 3D 变换。这些变换继承自包装Node 。
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) } } } }
与第一个片段相比,Model 节点现在有了一个子节点,其变换使其略高于立方体的位置。150
在三维坐标空间中相对于立方体的中心。
Model { Node { y: 150
然后是Rectangle 项。当把它添加到Node 下时,三维世界和二维世界的边界会在内部交叉,但这对应用程序设计者来说是透明的。一个不可见的content item
会自动生成,允许矩形引用parent
并执行锚定。节点的 3D 变换将应用于整个 2D 子树。在本示例中,这意味着旋转将与立方体的旋转相匹配。
Node { y: 150 Rectangle { anchors.horizontalCenter: parent.horizontalCenter
二维和三维坐标空间
2D 项目继续使用Qt Quick 的坐标系:Y 轴从上到下,单位对应像素。三维节点则使用三维坐标系:Y 轴向上,单位对应厘米,受Camera 的透视投影影响。
默认情况下,顶层项的左上角位于节点的原点。这意味着,二维子树中的顶层项通常需要指定一个锚点,例如anchors.centerIn: parent
,或者像示例中那样,将水平中心锚定到父节点的水平中心,从而使二维内容水平居中于三维节点。
更多注意事项
- 虽然 2D 项目是与 3D 物体同步渲染的,但它们不参与照明,也不会投射阴影。
- Clipping 因此,剪贴可能无法达到预期效果,应避免使用。如果剪切对 2D 项目的设计至关重要,应用程序应明确回退到纹理渲染。这可以通过在 3D 节点下的顶级 中添加 来实现。
Item
layer.enabled: true
- 从 Qt 6.2 开始,输入将根据需要传递到 2D 项目。来自指向设备的输入必须在所声明项的childrenRect 范围内进行。
- 虽然在三维场景中添加二维项树的成本很低,但应避免在三维场景中添加过量(数百或更多)的二维子树,因为如果数量过多,可能会导致内存和图形资源使用量增加。请注意,这里指的是三维节点下独立的Item 子树的数量,而不是这些子树上二维项的总数。例如,上面的 QML 代码段只包含一个 2D 子树。
另请参阅 Qt Quick 3D - Quick Items Example和QQuickItem::mapFromGlobal().
© 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.