Сцены Qt Quick 3D с 2D-содержимым
2D-элементы в 3D-мире
Qt Quick 3D позволяет эффективно создавать и отрисовывать сцены, объединяющие 3D и 2D-элементы.
Что мы подразумеваем под объединённой 3D-2D сценой?
По своей природе объект View3D, представляющий 3D-видовую область в 2D-сцене, может быть легко объединён с элементами Qt Quick, такими как Rectangle, Image, Text, расположенными вокруг, под или над элементом 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-сцены.
Что если нам нужно разместить 2D-элементы внутри 3D-мира таким образом, чтобы они действительно участвовали во всех 3D-преобразованиях? Например, можно ли разместить элементы Rectangle и Text внутри 3D-мира так, чтобы они следовали за вращением куба и всегда располагались над ним?
В следующих разделах мы рассмотрим, как этого добиться. Хотя пример использует Rectangle и Text, в таком формате можно использовать любой контент Qt Quick, включая Qt Quick Controls, Shape, ShaderEffect, ParticleSystem.
Примечание: Существуют и другие подходы для интеграции 2D-содержимого с 3D-объектами. Добавление 2D-элементов к 3D-узлам позволяет свободно комбинировать 2D и 3D объекты в 3D-мире, но не позволяет отрисовывать 2D-содержимое на поверхности 3D-объекта. Если целью является текстурирование 3D-модели с помощью контента, созданного Qt Quick, используйте свойство sourceItem Texture.
| Qt Quick-контент, используемый в качестве карты текстур | Элементы Qt Quick в 3D-сцене |
|---|---|
Добавление 2D-элементов к 3D-узлам
Ключевым элементом является возможность Object3D принимать дочерние объекты Item и обрабатывать их особым образом. Object3D — базовый класс для типа Node. Это означает, что любые Node, а также типы, такие как Model, принимают дочерние элементы Item.
Начиная с Qt 6.0, добавление 2D-элемента к 3D-узлу больше не приводит к отрисовке 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 относительно центра куба, в 3D-пространстве координат.
Model {
Node {
y: 150 Затем идёт элемент Rectangle. При добавлении его под Node, границы 3D и 2D миров пересекаются внутри, но это остаётся прозрачным для разработчика приложения. Невидимый content item генерируется автоматически, позволяя Rectangle ссылаться на parent и выполнять привязку. 3D-преобразование от Node применяется ко всему 2D-поддереву. В примере это означает, что вращение будет соответствовать вращению куба.
Node {
y: 150
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter Пространства координат в 2D и 3D
2D-элементы по-прежнему используют систему координат Qt Quick: ось Y направлена сверху вниз, а единицы соответствуют пикселям. 3D-узлы, с другой стороны, используют 3D-систему координат: ось Y направлена вверх, а единицы соответствуют сантиметрам, которые влияют на перспективную проекцию камеры.
По умолчанию верхний левый угол верхнего элемента размещается в начале координат Node. Это означает, что верхний элемент 2D-поддерева часто должен указывать точку привязки, например anchors.centerIn: parent, или, как в примере, привязывать центр по горизонтали к центру по горизонтали родительского элемента, тем самым центрируя 2D-содержимое по горизонтали над 3D-узлом.
Дополнительные соображения
- Хотя 2D-элементы отрисовываются совместно с 3D-объектами, они не участвуют в освещении и не будут отбрасывать тени.
-
Обрезка может не работать как ожидается и следует избегать её. Если обрезка существенна для дизайна 2D-элементов, приложение должно явно перейти к отрисовке в текстуру. Этого можно добиться, добавив
layer.enabled: trueк верхнемуItemпод 3D-узлом. - Начиная с Qt 6.0, ввод с клавиатуры, мыши и сенсорного экрана не передаётся 2D-элементам, поэтому они не будут интерактивными.
- Хотя добавление дерева 2D-элементов в 3D-сцену довольно недорого, следует избегать чрезмерного количества (сотни или более) 2D-поддеревьев в 3D-сцене, так как в больших количествах это может привести к увеличению использования памяти и графических ресурсов. Обратите внимание, что это относится к количеству отдельных Item поддеревьев под 3D-узлами, а не к общему количеству 2D-элементов в этих поддеревьях. Например, в приведённом выше фрагменте QML содержится только одно 2D-поддерево.
См. также Qt Quick 3D - Пример элементов Qt Quick.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qtquick3d-2d.html