虚拟助理

Qt Quick 虚拟助理 "应用程序可展示虚拟助理的三维模型,并使用 QML 和时间轴创建动态动画。

虚拟助理示例演示了如何通过时间轴动画让虚拟助理的三维模型栩栩如生,从而提高用户参与度和互动性。

导入 3D 模型

要在Qt Design Studio 中加载模型,只需将 .gltf 文件导入到项目中即可。然后,Qt Design Studio 会自动创建表示对象的 QML 文件。它还会生成必要的资产。如果没有Qt Design Studio ,则必须手动运行Balsam工具。在本例中,对生成的 QML 文件进行了修改,以引入状态、动画和附加的不可见模型,从而可以选取虚拟助手的特定部分。

准备场景环境

该场景使用 HDR 图像创建天空盒并提供自然光。

        environment: ExtendedSceneEnvironment {
            backgroundMode: SceneEnvironment.SkyBox
            lightProbe: Texture { source: Constants.sceneName }
            antialiasingMode: SceneEnvironment.MSAA
            antialiasingQuality: SceneEnvironment.VeryHigh
            fxaaEnabled: true
            probeExposure: 0.6
            probeOrientation: Qt.vector3d(0, settingsPanel.skyboxRotation, 0)
            specularAAEnabled: true
            tonemapMode: SceneEnvironment.TonemapModeLinear
            vignetteEnabled: true
            vignetteRadius: 0.15
        }

摄像机选项

可在设置面板中更改摄像机属性。您可以使用滑块操作视场 (FOV) 和天空盒旋转。复选框启用OrbitCameraController ,还可以交互式更改摄像机位置和旋转。

动画

动画使用多个Timeline 时间线和Keyframe 关键帧创建。每个Timeline 都与虚拟助手的不同状态相连。当状态发生变化时,连接的动画会立即开始播放。每个动画结束时,对象会返回默认状态并恢复默认值,如模型nodes 的位置和旋转。动画会改变骨架中节点的属性值,并修改不同morph targets 的权重,从而为脸部元素(眼睛、嘴巴)制作动画。

使用动画面板上的按钮可以运行动画。您还可以点击特定的模型元素,如手、下半身和脸部,以激活与模型该部分相关的动画。

骨骼动画
  • 进入动画
  • 退出动画
  • 探索场景动画
  • 后空翻动画
  • 低身弹跳动画
  • 左右挥手动画
变形目标动画
  • 面部动画(快乐和悲伤)

在模型左手上实现挥手动画的示例:

Timeline {
    id: leftHandWavingTimeline
    animations: [
        TimelineAnimation {
            id: leftHandWavingAnimation
            onFinished: node.restoreDefaults()
            running: false
            loops: 1
            duration: 2000
            to: 2000
            from: 0
        }
    ]
    startFrame: 0
    endFrame: 2000
    enabled: false

    KeyframeGroup {
        target: hand_l
        property: "x"
        Keyframe {
            value: 2.89
            frame: 400
        }

        Keyframe {
            value: 2.89
            frame: 1600
        }

        Keyframe {
            value: 1.89
            frame: 2000
        }
    }

    KeyframeGroup {
        target: hand_l
        property: "y"
        Keyframe {
            value: 1
            frame: 400
        }

        Keyframe {
            value: 1
            frame: 1600
        }

        Keyframe {
            value: 0.5
            frame: 2000
        }
    }

    KeyframeGroup {
        target: hand_l
        property: "z"
        Keyframe {
            value: 1
            frame: 400
        }

        Keyframe {
            value: 1
            frame: 1600
        }

        Keyframe {
            value: -0.1
            frame: 2000
        }
    }

    KeyframeGroup {
        target: hand_l
        property: "eulerRotation.x"
        Keyframe {
            value: -15
            frame: 400
        }

        Keyframe {
            value: -5
            frame: 700
        }

        Keyframe {
            value: -15
            frame: 1000
        }

        Keyframe {
            value: -5
            frame: 1300
        }

        Keyframe {
            value: -15
            frame: 1600
        }

        Keyframe {
            value: -0.18
            frame: 2000
        }
    }

    KeyframeGroup {
        target: hand_l
        property: "eulerRotation.y"
        Keyframe {
            value: -15
            frame: 400
        }

        Keyframe {
            value: -30
            frame: 1600
        }

        Keyframe {
            value: -145
            frame: 2000
        }

        Keyframe {
            value: -40
            frame: 700
        }
    }

    KeyframeGroup {
        target: hand_l
        property: "eulerRotation.z"
        Keyframe {
            value: -88
            frame: 400
        }

        Keyframe {
            value: -30
            frame: 700
        }

        Keyframe {
            value: -86.05
            frame: 1000
        }

        Keyframe {
            value: -30
            frame: 1300
        }

        Keyframe {
            value: -86.05
            frame: 1600
        }

        Keyframe {
            value: -178.92
            frame: 2000
        }
    }

    KeyframeGroup {
        target: morphTarget38
        property: "weight"
        Keyframe {
            value: 1
            frame: 0
        }

        Keyframe {
            value: 0.25
            frame: 400
        }

        Keyframe {
            value: 0.25
            frame: 1600
        }

        Keyframe {
            value: 1
            frame: 2000
        }
    }

    KeyframeGroup {
        target: morphTarget42
        property: "weight"
        Keyframe {
            value: 0
            frame: 2000
        }

        Keyframe {
            value: 0.75
            frame: 1600
        }

        Keyframe {
            value: 0.75
            frame: 400
        }

        Keyframe {
            value: 0
            frame: 0
        }
    }

    KeyframeGroup {
        target: morphTarget27
        property: "weight"
        Keyframe {
            value: 0
            frame: 0
        }

        Keyframe {
            value: 1
            frame: 400
        }

        Keyframe {
            value: 1
            frame: 1600
        }

        Keyframe {
            value: 0
            frame: 2000
        }
    }

    KeyframeGroup {
        target: morphTarget28
        property: "weight"
        Keyframe {
            value: 1
            frame: 2000
        }

        Keyframe {
            value: 0
            frame: 1600
        }

        Keyframe {
            value: 0
            frame: 400
        }

        Keyframe {
            value: 1
            frame: 0
        }
    }
}

示例项目 @ code.qt.io

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