Qt Quick 3D - 虚拟助手示例

Qt Quick 应用程序,展示了使用 QML 和时间轴动态创建的虚拟助手三维模型的演示。

虚拟助手示例 展示了如何通过时间轴动画使虚拟助手的三维模型栩栩如生,增加用户参与度和交互。示例可以在 QtDesignStudio 和 QtCreator 中运行和编辑。

导入 3D 模型

要在 QtDesignStudio 中加载模型,只需将 .gltf 文件导入到项目中即可。QtDesignStudio 自动创建代表该对象的 qml 文件,并会生成必要的资产。如果没有 QtDesignStudio,您需要使用 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
        }

相机选项

您可以通过 SettingsPanel 更改相机属性。您可以使用滑块操作相机的 FOV 和天空盒旋转。复选框启用 OrbitCameraController,允许使用鼠标和键盘按钮更改相机位置、旋转等。

动画

动画使用多个 Timeline 时间轴和 Keyframe 关键帧创建。每个 Timeline 时间轴都与不同的 VirtualAssistant 状态相关联。动画在状态改变后立即开始播放。每个动画结束时,对象返回默认状态并恢复模型的默认值,如位置和旋转 节点。动画更改我们骨架中节点的属性值,并修改不同的 形态目标 的权重来动画化面部元素(眼睛、嘴巴)。

要运行动画,您可以使用左侧场景中的控制面板上的按钮,也可以点击特定的模型元素(如手、下半身和面部)以激活与该模型部分相关的动画。

骨骼 动画
  • 入场动画
  • 退场动画
  • 场景探索动画
  • 翻滚动画
  • 弹跳动画
  • 左右手挥动画
形态目标动画
  • 面部动画(快乐和悲伤)

模型左手摇动动画的示例实现

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
        }
    }
}

文件

© 2024 The Qt Company Ltd. 本文件中包含的文档贡献归各自的所有者所有。提供的文档受免费软件基金会发布的GNU自由文档许可证版本1.3的条款约束。Qt及其相关标志是芬兰以及世界其他地区的The Qt Company Ltd的商标。所有其他商标均归其各自所有者所有。