Kuesa Car-Scene QML Example
QtQuick and Qt3D integration
The car-scene example relies on the regular QtQuick and Qt 3D APIs to instantiate a QtQuick based application that combines Qt 3D based content with a 2D UI overlay.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | Item {
id: mainRoot
// 3D Content
Material.theme: Material.Dark
Material.accent: Material.Blue
Item {
id: baseUI
anchors.fill: parent
Wind {
id: wind
anchors.fill: parent
visible: menu.useOpacityMask
}
Scene3D {
id: scene3D
anchors.fill: parent
focus: true
multisample: true
aspects: ["input", "animation", "logic"]
// Root Scene Entity
MainScene {
id: sceneContent
|
Filename: car-scene/qml/main.qml
SceneEntity
Kuesa provides the [SceneEntity ] element which holds collections of Qt 3D assets accessible by name.
| import Kuesa 2.0 as Kuesa
import Kuesa.Effects 2.0 as Effects
Kuesa.SceneEntity {
id: scene
|
Filename: car-scene/qml/MainScene.qml
Importing a glTF2 File
In order to load a glTF2 file, Kuesa provides the [GLTF2Importer ] element. If the sceneEntity property is set to a valid [SceneEntity ] instance, Qt 3D assets generated while parsing the file will be automatically added to the various asset collections.
| // Loads GLTF 2.0 asset
Kuesa.GLTF2Importer {
sceneEntity: scene
source: "file:" + _assetsDir + "/models/car/DodgeViper" + _modelSuffix + ".gltf"
}
|
Filename: car-scene/qml/MainScene.qml
Usually, you will want to interact with some elements of your scene. The [Asset ] element allows to retrieve an asset by name. If the asset for a given name really exist in the specified collection, the node property allows you to access the underlying asset instance.
You can use the Kuesa Studio gltfInspector to introspect a glTF2 scene files and find the names of the various assets it contains.
For instance you might want to select a Camera by name.
| Kuesa.Asset {
id: sweepCam
collection: scene.cameras
name: "SweepCam"
}
|
Filename: car-scene/qml/MainScene.qml
Once retrieved, you can create binding on some of the Camera properties.
| QQ2.Binding {
target: sweepCam.node
property: "aspectRatio"
value: mainCamera.aspectRatio
}
|
Filename: car-scene/qml/MainScene.qml
Similarly you could retrieve a Material asset
1
2
3
4
5
6
7
8
9
10
11
12 | // We create a baseColorFactor property. If the property exists in the node, it will be a proxy of the node property
// When we set the qml property, the node property will be updated accordingly
// When the node property is updated in C++, the qml property will be updated
// As soon as the node is changed, the qml property is updated if it has a C++ equivalent
Kuesa.Asset {
property color baseColorFactor: scene.carBaseColorFactor
id: carMaterial
collection: scene.materials
name: "Mat_CarPaint"
onBaseColorFactorChanged: console.log("Binding 1 works. Color: " + baseColorFactor)
onNodeChanged: scene.carBaseColorFactor = carMaterial.baseColorFactor
}
|
Filename: car-scene/qml/MainScene.qml
And create a binding on its properties to control the appearance of elements in the scene that use that material.
| property var baseColorFactorProp: carMaterial.baseColorFactor
onBaseColorFactorPropChanged: console.log("Binding 2 works. Color: " + baseColorFactorProp)
|
Filename: car-scene/qml/MainScene.qml
Playing Animations
The [AnimationPlayer ] allows to control the playback of animation clips that can be retrieve by name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | Kuesa.AnimationPlayer {
id: hoodAnimator
sceneEntity: scene
clock: Clock { }
clip: "HoodAction"
}
Kuesa.AnimationPlayer {
id: leftDoorAnimator
sceneEntity: scene
clock: Clock { }
clip: "DoorLAction"
}
Kuesa.AnimationPlayer {
id: rightDoorAnimator
sceneEntity: scene
clock: Clock { }
clip: "DoorRAction"
}
|
Filename: car-scene/qml/MainScene.qml
Adding Post Processing Effects
First you need to instantiate the effects you want to use.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | Effects.OpacityMask {
id: opacityMaskEffect
mask: TextureLoader {
source: "qrc:/opacity_mask.png";
generateMipMaps: false
}
premultipliedAlpha: true // This is what Scene3D/QtQuick expects
}
Effects.BloomEffect {
id: bloomFx
threshold: 0.34
blurPassCount: 2
}
|
Filename: car-scene/qml/MainScene.qml
Once you have created the effects, they need to be added to the [ForwardRenderer ] FrameGraph. The order in which they are added dictates the order in which they are applied.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | RenderSettings {
// FrameGraph
activeFrameGraph: Kuesa.ForwardRenderer {
id: frameGraph
camera: scene.animated && sweepCam.node ? sweepCam.node : mainCamera
postProcessingEffects: {
var effects = []
if (useBloomEffect)
effects.push(bloomFx)
if (useOpacityMask)
effects.push(opacityMaskEffect)
return effects
}
skinning: showSkybox
backToFrontSorting: true
toneMappingAlgorithm: Effects.ToneMappingAndGammaCorrectionEffect.Reinhard
// showDebugOverlay: true
}
},
|
Filename: car-scene/qml/MainScene.qml
Updated on 2022-10-18 at 11:12:53 +0200