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