Qt Quick 3D 基础与应用

发布于:2025-08-04 ⋅ 阅读:(13) ⋅ 点赞:(0)

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.15

Window {
    id: mainWindow
    visible: true
    width: 800
    height: 600
    title: "Qt Quick 3D 基础场景"
    
    // 3D 视图容器
    View3D {
        id: view3d
        anchors.fill: parent
        
        // 3D 场景根节点
        Scene {
            id: scene
            
            // 相机
            PerspectiveCamera {
                id: camera
                position: Qt.vector3d(0, 0, 10)  // 相机位置 (x, y, z)
                eulerRotation: Qt.vector3d(0, 0, 0)  // 相机旋转
                fieldOfView: 60  // 视场角
            }
            
            // 光源
            DirectionalLight {
                id: dirLight
                eulerRotation: Qt.vector3d(45, 45, 0)  // 光源方向
                color: Qt.rgba(1, 1, 0.9, 1)  // 暖白色光
                intensity: 1.0  // 光强度
            }
            
            // 3D 模型 - 内置立方体
            Model {
                id: cube
                source: "#Cube"  // 使用内置几何体
                position: Qt.vector3d(0, 0, 0)  // 模型位置
                
                // 材质
                materials: [
                    DefaultMaterial {
                        id: cubeMaterial
                        diffuseColor: "#4a90e2"  // 漫反射颜色
                    }
                ]
                
                // 旋转动画
                NumberAnimation on eulerRotation.y {
                    from: 0
                    to: 360
                    duration: 5000
                    loops: Animation.Infinite
                }
            }
            
            // 地面
            Model {
                id: ground
                source: "#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: 20
    anchors.centerIn: parent
    
    View3D {
        width: 150
        height: 150
        
        Scene {
            PerspectiveCamera { position: Qt.vector3d(0, 0, 5) }
            DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }
            
            Model {
                source: "#Cube"  // 立方体
                materials: [DefaultMaterial { diffuseColor: "red" }]
            }
        }
    }
    
    View3D {
        width: 150
        height: 150
        
        Scene {
            PerspectiveCamera { position: Qt.vector3d(0, 0, 5) }
            DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }
            
            Model {
                source: "#Sphere"  // 球体
                materials: [DefaultMaterial { diffuseColor: "green" }]
            }
        }
    }
    
    View3D {
        width: 150
        height: 150
        
        Scene {
            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.15

Window {
    width: 800
    height: 600
    visible: true
    title: "加载外部 3D 模型"
    
    View3D {
        anchors.fill: parent
        
        Scene {
            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: importedModel
                source: "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: 0
                    to: 360
                    duration: 20000
                    loops: 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.Linear
                minificationFilter: 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: parent
    camera: activeCamera  // 使用当前激活的相机
    
    property Camera activeCamera: camera1
    
    Scene {
        // 相机 1: 正面视角
        PerspectiveCamera {
            id: camera1
            position: Qt.vector3d(0, 0, 10)
        }
        
        // 相机 2: 顶部视角
        PerspectiveCamera {
            id: camera2
            position: Qt.vector3d(0, 10, 0)
            eulerRotation: Qt.vector3d(90, 0, 0)
        }
        
        // 相机 3: 侧面视角
        PerspectiveCamera {
            id: camera3
            position: 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.bottom
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.bottomMargin: 20
    spacing: 10
    
    Button {
        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: view3d
    anchors.fill: parent
    
    Scene {
        PerspectiveCamera {
            id: camera
            position: Qt.vector3d(0, 5, 10)
            eulerRotation: Qt.vector3d(20, 0, 0)
            
            // 相机控制属性
            property real orbitSpeed: 0.5
            property real zoomSpeed: 0.1
            property 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: parent
        drag.active: pressed
        wheel.enabled: true
        
        property var lastMousePos
        
        onPressed: {
            lastMousePos = Qt.point(mouseX, mouseY)
        }
        
        onMouseXChanged: {
            if (pressed) {
                // 左右拖动 - 旋转相机环绕物体
                var delta = mouseX - lastMousePos.x
                camera.eulerRotation.y += delta * camera.orbitSpeed
                lastMousePos.x = mouseX
            }
        }
        
        onMouseYChanged: {
            if (pressed) {
                // 上下拖动 - 旋转相机仰角
                var delta = mouseY - lastMousePos.y
                var newPitch = camera.eulerRotation.x - delta * camera.orbitSpeed
                // 限制仰角范围
                if (newPitch > -89 && newPitch < 89) {
                    camera.eulerRotation.x = newPitch
                }
                lastMousePos.y = mouseY
            }
        }
        
        onWheel: {
            // 鼠标滚轮 - 缩放
            var delta = wheel.angleDelta.y
            var newZ = camera.position.z - delta * camera.zoomSpeed
            // 限制缩放范围
            if (newZ > 3 && newZ < 20) {
                camera.position.z = newZ
            }
        }
    }
}

五、3D 动画与交互

1. 模型动画
Model {
    id: animatedModel
    source: "models/character.glb"  // 包含骨骼动画的模型
    
    // 动画控制器
    AnimationController {
        id: animController
        animation: animatedModel.animations[0]  // 使用第一个动画
        running: true
        loops: Animation.Infinite
    }
    
    // 动画切换
    function playAnimation(index) {
        if (index >= 0 && index < animatedModel.animations.length) {
            animController.animation = animatedModel.animations[index]
            animController.restart()
        }
    }
}

// 动画控制按钮
Row {
    spacing: 10
    anchors.bottom: parent.bottom
    anchors.horizontalCenter: parent.horizontalCenter
    
    Button {
        text: "走路"
        onClicked: animatedModel.playAnimation(0)
    }
    Button {
        text: "跑步"
        onClicked: animatedModel.playAnimation(1)
    }
    Button {
        text: "跳跃"
        onClicked: animatedModel.playAnimation(2)
    }
}
2. 3D 物体拾取
View3D {
    id: view3d
    anchors.fill: parent
    
    Scene {
        id: scene
        PerspectiveCamera {
            id: camera
            position: Qt.vector3d(0, 5, 10)
            eulerRotation: Qt.vector3d(20, 0, 0)
        }
        
        DirectionalLight { eulerRotation: Qt.vector3d(45, 45, 0) }
        
        // 可点击的 3D 物体
        Repeater {
            model: 5
            
            delegate: Model {
                id: clickableModel
                source: "#Sphere"
                position: Qt.vector3d((index - 2) * 2, 0, 0)
                scale: Qt.vector3d(0.8, 0.8, 0.8)
                
                materials: [
                    DefaultMaterial {
                        id: mat
                        diffuseColor: isSelected ? "red" : "blue"
                    }
                ]
                
                property bool isSelected: false
                
                // 3D 拾取器
                Picker {
                    id: picker
                    onPressed: {
                        // 重置其他物体
                        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: parent
        onClicked: {
            // 从点击位置发射射线检测碰撞
            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.15

Window {
    width: 1024
    height: 768
    visible: true
    title: "2D 与 3D 混合界面"
    
    // 3D 场景作为背景
    View3D {
        anchors.fill: parent
        
        Scene {
            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: 0
                    to: 360
                    duration: 10000
                    loops: 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: topBar
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.right: parent.right
        height: 50
        color: "rgba(0, 0, 0, 0.7)"
        
        Text {
            anchors.centerIn: parent
            color: "white"
            font.pointSize: 16
            text: "3D 模型查看器"
        }
    }
    
    Column {
        anchors.left: parent.left
        anchors.top: topBar.bottom
        anchors.bottom: parent.bottom
        spacing: 10
        padding: 10
        
        Button {
            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: scaleSlider
            width: 100
            from: 0.5
            to: 2.0
            value: 1.0
            onValueChanged: {
                var sphere = view3d.scene.children[2];
                if (sphere) {
                    sphere.scale = Qt.vector3d(value, value, value);
                }
            }
        }
    }
    
    // 信息面板
    Rectangle {
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        width: 200
        height: 150
        color: "rgba(255, 255, 255, 0.8)"
        radius: 5
        padding: 10
        
        Column {
            spacing: 5
            
            Text {
                text: "模型信息"
                font.bold: true
            }
            
            Text {
                text: "类型: 球体"
            }
            
            Text {
                text: "缩放: " + scaleSlider.value.toFixed(1) + "x"
            }
        }
    }
}

七、总结

Qt Quick 3D 为开发者提供了在 QML 环境中创建和集成 3D 内容的强大能力:

  1. 核心组件:通过 View3D、Scene、Camera、Light 和 Model 构建基础 3D 场景
  2. 模型处理:支持内置几何体和外部模型文件加载
  3. 材质系统:提供丰富的材质属性和纹理映射能力
  4. 相机控制:支持多视角切换和交互控制
  5. 动画与交互:实现模型动画、相机控制和 3D 物体拾取
  6. 混合界面:无缝整合 2D UI 元素与 3D 场景

Qt Quick 3D 特别适合需要在应用中添加 3D 元素但不需要复杂 3D 引擎功能的场景,如产品展示、数据可视化、教育应用等。其与 QML 的深度集成使得开发者能够利用现有的 Qt Quick 知识快速构建富 3D 体验的应用程序。


网站公告

今日签到

点亮在社区的每一天
去签到