Qt Quick 3D 基础与应用
Qt Quick 3D 是 Qt 框架中用于创建 3D 内容的模块,它允许开发者在 QML 环境中轻松集成 3D 元素,与 2D UI 组件无缝协作。无论是简单的 3D 模型展示还是复杂的交互式 3D 场景,Qt Quick 3D 都提供了直观且高效的开发方式。本文将深入解析 Qt Quick 3D 的核心概念和应用技术。
一、Qt Quick 3D 基础组件
1. 基本 3D 场景结构
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick3D 1.15Window {id: mainWindowvisible: truewidth: 800height: 600title: "Qt Quick 3D 基础场景"// 3D 视图容器View3D {id: view3danchors.fill: parent// 3D 场景根节点Scene {id: scene// 相机PerspectiveCamera {id: cameraposition: Qt.vector3d(0, 0, 10) // 相机位置 (x, y, z)eulerRotation: Qt.vector3d(0, 0, 0) // 相机旋转fieldOfView: 60 // 视场角}// 光源DirectionalLight {id: dirLighteulerRotation: Qt.vector3d(45, 45, 0) // 光源方向color: Qt.rgba(1, 1, 0.9, 1) // 暖白色光intensity: 1.0 // 光强度}// 3D 模型 - 内置立方体Model {id: cubesource: "#Cube" // 使用内置几何体position: Qt.vector3d(0, 0, 0) // 模型位置// 材质materials: [DefaultMaterial {id: cubeMaterialdiffuseColor: "#4a90e2" // 漫反射颜色}]// 旋转动画NumberAnimation on eulerRotation.y {from: 0to: 360duration: 5000loops: Animation.Infinite}}// 地面Model {id: groundsource: "#Plane" // 平面几何体position: Qt.vector3d(0, -2, 0)scale: Qt.vector3d(5, 1, 5) // 缩放平面materials: [DefaultMaterial {diffuseColor: "#f0f0f0"}]}}}
}
2. 核心组件解析
- View3D: 3D 渲染的容器,负责将 3D 场景绘制到屏幕上
- Scene: 3D 场景的根节点,所有 3D 元素的父容器
- Camera: 定义观察视角,支持透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)
- Light: 提供场景照明,包括方向光、点光源、聚光灯等
- Model: 3D 模型容器,可加载内置几何体或外部模型文件
- Material: 定义模型表面的视觉属性,如颜色、纹理、光泽度等
二、3D 几何体与模型
1. 内置几何体
Qt Quick 3D 提供多种内置基础几何体:
// 内置几何体示例
Row {spacing: 20anchors.centerIn: parentView3D {width: 150height: 150Scene {PerspectiveCamera { position: Qt.vector3d(0, 0, 5) }DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }Model {source: "#Cube" // 立方体materials: [DefaultMaterial { diffuseColor: "red" }]}}}View3D {width: 150height: 150Scene {PerspectiveCamera { position: Qt.vector3d(0, 0, 5) }DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }Model {source: "#Sphere" // 球体materials: [DefaultMaterial { diffuseColor: "green" }]}}}View3D {width: 150height: 150Scene {PerspectiveCamera { position: Qt.vector3d(0, 0, 5) }DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }Model {source: "#Cylinder" // 圆柱体materials: [DefaultMaterial { diffuseColor: "blue" }]}}}
}
2. 加载外部 3D 模型
Qt Quick 3D 支持加载多种格式的外部模型:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick3D 1.15Window {width: 800height: 600visible: truetitle: "加载外部 3D 模型"View3D {anchors.fill: parentScene {PerspectiveCamera {position: Qt.vector3d(0, 5, 15)eulerRotation: Qt.vector3d(20, 0, 0)}DirectionalLight {eulerRotation: Qt.vector3d(45, 45, 0)intensity: 1.2}// 加载 glTF 格式模型Model {id: importedModelsource: "models/car.glb" // glTF 二进制格式position: Qt.vector3d(0, 0, 0)scale: Qt.vector3d(0.5, 0.5, 0.5) // 缩放模型// 模型加载状态监控onStatusChanged: {if (status === Model.Ready) {console.log("模型加载完成")} else if (status === Model.Error) {console.log("模型加载错误:", errorString)}}// 自动旋转NumberAnimation on eulerRotation.y {from: 0to: 360duration: 20000loops: Animation.Infinite}}// 地面Model {source: "#Plane"position: Qt.vector3d(0, -1, 0)scale: Qt.vector3d(10, 1, 10)materials: [DefaultMaterial {diffuseColor: "#e0e0e0"}]}}}
}
支持的模型格式包括:glTF 2.0 (.gltf, .glb)、Wavefront OBJ (.obj)、STL (.stl) 等。
三、材质与纹理
1. 基础材质属性
Model {source: "#Sphere"position: Qt.vector3d(0, 0, 0)scale: Qt.vector3d(2, 2, 2)materials: [DefaultMaterial {// 漫反射颜色diffuseColor: "#4a90e2"// 金属度 (0-1)metallic: 0.8// 粗糙度 (0-1)roughness: 0.3// 环境光遮蔽ambientOcclusion: 0.5// 自发光emissiveColor: "#1a1a33"emissiveIntensity: 0.5}]
}
2. 纹理映射
Model {source: "#Cube"position: Qt.vector3d(0, 0, 0)materials: [DefaultMaterial {// 漫反射纹理diffuseMap: Texture {source: "textures/wood_diffuse.jpg"magnificationFilter: Texture.LinearminificationFilter: Texture.LinearMipMapLinear}// 法线纹理 (增加表面细节)normalMap: Texture {source: "textures/wood_normal.jpg"normalScaling: Qt.vector2d(0.5, 0.5)}// 粗糙度纹理roughnessMap: Texture {source: "textures/wood_roughness.jpg"}// 金属度纹理metallicMap: Texture {source: "textures/wood_metallic.jpg"}}]
}
四、相机与视角控制
1. 多相机切换
View3D {anchors.fill: parentcamera: activeCamera // 使用当前激活的相机property Camera activeCamera: camera1Scene {// 相机 1: 正面视角PerspectiveCamera {id: camera1position: Qt.vector3d(0, 0, 10)}// 相机 2: 顶部视角PerspectiveCamera {id: camera2position: Qt.vector3d(0, 10, 0)eulerRotation: Qt.vector3d(90, 0, 0)}// 相机 3: 侧面视角PerspectiveCamera {id: camera3position: Qt.vector3d(10, 0, 0)eulerRotation: Qt.vector3d(0, 90, 0)}// 3D 物体Model {source: "#TorusKnot"materials: [DefaultMaterial { diffuseColor: "purple" }]}DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }}
}// 相机切换按钮
Row {anchors.bottom: parent.bottomanchors.horizontalCenter: parent.horizontalCenteranchors.bottomMargin: 20spacing: 10Button {text: "正面"onClicked: view3d.activeCamera = view3d.scene.camera1}Button {text: "顶部"onClicked: view3d.activeCamera = view3d.scene.camera2}Button {text: "侧面"onClicked: view3d.activeCamera = view3d.scene.camera3}
}
2. 鼠标控制相机
View3D {id: view3danchors.fill: parentScene {PerspectiveCamera {id: cameraposition: Qt.vector3d(0, 5, 10)eulerRotation: Qt.vector3d(20, 0, 0)// 相机控制属性property real orbitSpeed: 0.5property real zoomSpeed: 0.1property real panSpeed: 0.02}DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }Model {source: "#Suzanne" // 猴子头模型materials: [DefaultMaterial { diffuseColor: "#ff6b6b" }]}Model {source: "#Plane"position: Qt.vector3d(0, -2, 0)scale: Qt.vector3d(10, 1, 10)materials: [DefaultMaterial { diffuseColor: "#f0f0f0" }]}}// 鼠标控制相机MouseArea {anchors.fill: parentdrag.active: pressedwheel.enabled: trueproperty var lastMousePosonPressed: {lastMousePos = Qt.point(mouseX, mouseY)}onMouseXChanged: {if (pressed) {// 左右拖动 - 旋转相机环绕物体var delta = mouseX - lastMousePos.xcamera.eulerRotation.y += delta * camera.orbitSpeedlastMousePos.x = mouseX}}onMouseYChanged: {if (pressed) {// 上下拖动 - 旋转相机仰角var delta = mouseY - lastMousePos.yvar newPitch = camera.eulerRotation.x - delta * camera.orbitSpeed// 限制仰角范围if (newPitch > -89 && newPitch < 89) {camera.eulerRotation.x = newPitch}lastMousePos.y = mouseY}}onWheel: {// 鼠标滚轮 - 缩放var delta = wheel.angleDelta.yvar newZ = camera.position.z - delta * camera.zoomSpeed// 限制缩放范围if (newZ > 3 && newZ < 20) {camera.position.z = newZ}}}
}
五、3D 动画与交互
1. 模型动画
Model {id: animatedModelsource: "models/character.glb" // 包含骨骼动画的模型// 动画控制器AnimationController {id: animControlleranimation: animatedModel.animations[0] // 使用第一个动画running: trueloops: Animation.Infinite}// 动画切换function playAnimation(index) {if (index >= 0 && index < animatedModel.animations.length) {animController.animation = animatedModel.animations[index]animController.restart()}}
}// 动画控制按钮
Row {spacing: 10anchors.bottom: parent.bottomanchors.horizontalCenter: parent.horizontalCenterButton {text: "走路"onClicked: animatedModel.playAnimation(0)}Button {text: "跑步"onClicked: animatedModel.playAnimation(1)}Button {text: "跳跃"onClicked: animatedModel.playAnimation(2)}
}
2. 3D 物体拾取
View3D {id: view3danchors.fill: parentScene {id: scenePerspectiveCamera {id: cameraposition: Qt.vector3d(0, 5, 10)eulerRotation: Qt.vector3d(20, 0, 0)}DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }// 可点击的 3D 物体Repeater {model: 5delegate: Model {id: clickableModelsource: "#Sphere"position: Qt.vector3d((index - 2) * 2, 0, 0)scale: Qt.vector3d(0.8, 0.8, 0.8)materials: [DefaultMaterial {id: matdiffuseColor: isSelected ? "red" : "blue"}]property bool isSelected: false// 3D 拾取器Picker {id: pickeronPressed: {// 重置其他物体for (var i = 0; i < scene.children.length; i++) {var child = scene.children[i];if (child !== picker && child.isSelected !== undefined) {child.isSelected = false;}}// 选中当前物体clickableModel.isSelected = true;}}}}}// 鼠标区域用于拾取MouseArea {anchors.fill: parentonClicked: {// 从点击位置发射射线检测碰撞var pickResult = view3d.pick(mouseX, mouseY);if (pickResult) {console.log("选中物体:", pickResult.object.name);}}}
}
六、2D 与 3D 混合界面
Qt Quick 3D 允许 2D UI 元素与 3D 场景无缝融合:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick3D 1.15
import QtQuick.Controls 2.15Window {width: 1024height: 768visible: truetitle: "2D 与 3D 混合界面"// 3D 场景作为背景View3D {anchors.fill: parentScene {PerspectiveCamera {position: Qt.vector3d(0, 5, 15)eulerRotation: Qt.vector3d(20, 0, 0)}DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }Model {source: "#Sphere"materials: [DefaultMaterial { diffuseColor: "#4a90e2" }]NumberAnimation on eulerRotation.y {from: 0to: 360duration: 10000loops: Animation.Infinite}}Model {source: "#Plane"position: Qt.vector3d(0, -2, 0)scale: Qt.vector3d(10, 1, 10)materials: [DefaultMaterial { diffuseColor: "#f0f0f0" }]}}}// 2D UI 元素覆盖在 3D 场景上Rectangle {id: topBaranchors.top: parent.topanchors.left: parent.leftanchors.right: parent.rightheight: 50color: "rgba(0, 0, 0, 0.7)"Text {anchors.centerIn: parentcolor: "white"font.pointSize: 16text: "3D 模型查看器"}}Column {anchors.left: parent.leftanchors.top: topBar.bottomanchors.bottom: parent.bottomspacing: 10padding: 10Button {text: "旋转"onClicked: {// 控制 3D 模型var sphere = view3d.scene.children[2]; // 获取球体模型if (sphere) {sphere.eulerRotation.x += 90;}}}Button {text: "重置"onClicked: {var sphere = view3d.scene.children[2];if (sphere) {sphere.eulerRotation = Qt.vector3d(0, 0, 0);}}}Slider {id: scaleSliderwidth: 100from: 0.5to: 2.0value: 1.0onValueChanged: {var sphere = view3d.scene.children[2];if (sphere) {sphere.scale = Qt.vector3d(value, value, value);}}}}// 信息面板Rectangle {anchors.right: parent.rightanchors.bottom: parent.bottomwidth: 200height: 150color: "rgba(255, 255, 255, 0.8)"radius: 5padding: 10Column {spacing: 5Text {text: "模型信息"font.bold: true}Text {text: "类型: 球体"}Text {text: "缩放: " + scaleSlider.value.toFixed(1) + "x"}}}
}
七、总结
Qt Quick 3D 为开发者提供了在 QML 环境中创建和集成 3D 内容的强大能力:
- 核心组件:通过 View3D、Scene、Camera、Light 和 Model 构建基础 3D 场景
- 模型处理:支持内置几何体和外部模型文件加载
- 材质系统:提供丰富的材质属性和纹理映射能力
- 相机控制:支持多视角切换和交互控制
- 动画与交互:实现模型动画、相机控制和 3D 物体拾取
- 混合界面:无缝整合 2D UI 元素与 3D 场景
Qt Quick 3D 特别适合需要在应用中添加 3D 元素但不需要复杂 3D 引擎功能的场景,如产品展示、数据可视化、教育应用等。其与 QML 的深度集成使得开发者能够利用现有的 Qt Quick 知识快速构建富 3D 体验的应用程序。