- Qt 6.7
- Qt Quick 3D
- Qt Quick 3D Examples and Tutorials
- Qt Quick 3D - Virtual Assistant Example
- Qt Quick 3D | Commercial or GPLv3

# Qt Quick 3D - Virtual Assistant Example

Qt Quick application that presents a 3D model of a virtual assistant with dynamic animations created using QML and timelines.

Virtual Assistant Example demonstrates how to bring a 3D model of a virtual assistant to life through timeline animations, increasing user engagement and interaction. The example can be run and edited in both QtDesignStudio and QtCreator.

#### Importing 3D Model

To load the model in QtDesingStudio it is enough to import the .gltf file to the project. QtDesignStudio automatically create a qml file that represents the object and it wil also generate necessary assets. Without QtDesignStudio you need to use balsam tool, and run it manually. In this example the generated qml file was modified to introduce the states, animations and some additional invicible models that allows to pick specific parts of the Virtual Assistant.

#### Preparing SceneEnvironment Scene Environment

Scene use HDR images to create a skybox and to provide natural lighthing.

             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
             }

#### Camera Options

Camera properties can be changed from the `SettingsPanel`. You can manipulate the camera FOV, skybox rotation using sliders. The checkbox enable the OrbitCameraController that allows to change camera position, rotation etc. using mouse and keyboards buttons.

#### Animations

The animations are created using multiple Timeline timelines and Keyframe keyframes. Each Timeline Timeline is connected with different state of the `VirtualAssistant`. The animations starts playing immadiately when the state change. At the end of each animation the object returns to the default state and restore the default values like position and rotation of the model nodes. The animations change the properties values of the nodes in our skeleton and also modify the weight of different morph targets to animate the face elements (eyes, mouth).

To run the animation you can use the button on ControlPanel on the left side of the scene or you can also click on specific model elements like hands, lower body and face to activate animation related to that part of the model.

##### Skeleton animations

- Entry animation
- Exit animation
- Explore scene animation
- Backflip animation
- Bouncing animation
- Right and Left hand waving animation

##### Morph Target animations

- Face animations (Happy and Sad)

Sample implementation of waving animation on the model's left hand:

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

Files:

- virtualassistant/CMakeLists.txt
- virtualassistant/Main.qml
- virtualassistant/Main/Main.qml
- virtualassistant/Main/QtVirtualAssistant_qml_module_dir_map.qrc
- virtualassistant/Main/qmldir
- virtualassistant/VirtualAssistant.qmlproject
- virtualassistant/asset_imports/CMakeLists.txt
- virtualassistant/asset_imports/Quick3DAssets/CMakeLists.txt
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/CMakeLists.txt
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/RobotHeart.qml
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/RobotHeart_qml_module_dir_map.qrc
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/RobotHeartplugin_Quick3DAssets_RobotHeartPlugin.cpp
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/RobotHeartplugin_Quick3DAssets_RobotHeartPlugin_in.cpp
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/RobotHeartplugin_init.cpp
- virtualassistant/asset_imports/Quick3DAssets/RobotHeart/qmldir
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/CMakeLists.txt
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/VirtualAssistant.qml
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/VirtualAssistant_qml_module_dir_map.qrc
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/VirtualAssistantplugin_Quick3DAssets_VirtualAssistantPlugin.cpp
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/VirtualAssistantplugin_Quick3DAssets_VirtualAssistantPlugin_in.cpp
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/VirtualAssistantplugin_init.cpp
- virtualassistant/asset_imports/Quick3DAssets/VirtualAssistant/qmldir
- virtualassistant/content/App.qml
- virtualassistant/content/CMakeLists.txt
- virtualassistant/content/ControlPanel.qml
- virtualassistant/content/Screen01.ui.qml
- virtualassistant/content/SettingsPanel.qml
- virtualassistant/content/qmldir
- virtualassistant/content/robotassistant_qml_module_dir_map.qrc
- virtualassistant/content/robotassistantplugin_init.cpp
- virtualassistant/content/robotassistantplugin_robotassistantPlugin.cpp
- virtualassistant/content/robotassistantplugin_robotassistantPlugin_in.cpp
- virtualassistant/imports/CMakeLists.txt
- virtualassistant/imports/Constants/CMakeLists.txt
- virtualassistant/imports/Constants/Constants.qml
- virtualassistant/imports/Constants/Constants_qml_module_dir_map.qrc
- virtualassistant/imports/Constants/Constantsplugin_VirtualAssistant_ConstantsPlugin.cpp
- virtualassistant/imports/Constants/Constantsplugin_VirtualAssistant_ConstantsPlugin_in.cpp
- virtualassistant/imports/Constants/Constantsplugin_init.cpp
- virtualassistant/imports/Constants/qmldir
- virtualassistant/src/main.cpp