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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt 3D Studio.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\page qt3d-runtime-scenecppapi.html
\title Advanced Scene Manipulation via the Qt 3D Studio Runtime Private C++ Classes
In addition to the \l {Qt 3D Studio Runtime C++ Classes}}{public C++ API},
applications needing direct access to the scenegraph of the presentations
loaded from \c{.uip} files can use the runtime's private C++ classes.
\note These classes offer no source or binary compatibility guarantees.
\note There is no documentation provided for the private classes. Refer to
the examples, this page, and the header files instead.
To link against the module, add this line to your \l qmake \c .pro file:
\badcode
QT += 3dstudioruntime2-private
\endcode
Then add the following include statement to the application sources:
\badcode
#include <private/q3dsengine_p.h>
#include <private/q3dsuippresentation_p.h>
\endcode
To access the Q3DSEngine instance, call Q3DSPresentation::engine(). This
applies also to Qt Quick applications: the Presentation item in the QML
code is an instance of a subclass of Q3DSPresentation, so once it gets
passed to C++ code, it can be used as a Q3DSPresentation. Accessing the
engine is only possible when a presentation is loaded. If the code needing
access to the scene is not invoked by some user interaction but rather has
to be done at startup, connect the execution of the C++ logic to a signal
like Studio3D::presentationLoaded().
Check out the \l{Qt 3D Studio Runtime: Dynamic Scene Manipulation C++
Example}{scenemanip example} for a demonstration of manipulating the Qt 3D
Studio scene from C++ in a Qt Quick application.
The next step is to get access to the Qt 3D Studio object tree. Query the
Q3DSUipPresentation via Q3DSEngine::presentation(). There is a separate
object tree for each subpresentation. Q3DSEngine::presentationCount()
allows iterating through all of them:
\badcode
int presentationCount() const;
Q3DSUipPresentation *presentation(int index = 0) const;
Q3DSUipPresentation *presentationByName(const QString &name) const;
\endcode
The Q3DSUipPresentation instance owns two object trees: one for the scene
(that maps mostly 1:1 to the scene, layer, camera, light, model, etc. tree
in the left side of the Timline in the Qt 3D Studio editor) and one for the
slides.
To access these, use the following accessors:
\badcode
Q3DSScene *scene() const;
Q3DSSlide *masterSlide() const;
\endcode
Support for dynamically manipulating the slide structure is limited as of
now. Certain related operations, like adding or removing animation tracks
at runtime is also limited for the time being. For the rest of this
document, we will focus on the scene itself.
The scenegraph is quite similar to the Qt Quick scenegraph and QSGNode when
it comes to the management of child and sibling nodes. Adding and removing
child nodes happens using a very similar API. The equivalent of QSGNode in
the Qt 3D Studio world is Q3DSGraphObject. For application purposes the
most important member functions are:
\badcode
Type type() const
Q3DSGraphObject *parent() const
Q3DSGraphObject *firstChild() const
Q3DSGraphObject *lastChild() const
Q3DSGraphObject *nextSibling() const
Q3DSGraphObject *previousSibling() const
int childCount() const;
Q3DSGraphObject *childAtIndex(int idx) const;
void removeChildNode(Q3DSGraphObject *node);
void removeAllChildNodes();
void prependChildNode(Q3DSGraphObject *node);
void appendChildNode(Q3DSGraphObject *node);
void insertChildNodeBefore(Q3DSGraphObject *node, Q3DSGraphObject *before);
void insertChildNodeAfter(Q3DSGraphObject *node, Q3DSGraphObject *after);
void reparentChildNodesTo(Q3DSGraphObject *newParent);
virtual void applyPropertyChanges(const Q3DSPropertyChangeList &changeList);
void notifyPropertyChanges(const Q3DSPropertyChangeList &changeList, int changeFlags = -1);
QVector<QByteArray> propertyNames() const;
QVector<QVariant> propertyValues() const;
QVariant property(const char *name);
bool setProperty(const char *name, const QVariant &v);
QVector<QByteArray> dynamicPropertyNames() const;
QVector<QVariant> dynamicPropertyValues() const;
QVariantMap dynamicProperties() const;
void clearDynamicProperties();
Q3DSPropertyChangeList applyDynamicProperties(const QVariantMap &v);
\endcode
Q3DSLayerNode, Q3DSCameraNode, Q3DSLightNode, Q3DSModelNode, Q3DSGroupNode,
Q3DSTextNode are all subclasses of Q3DSNode which in turn is a
Q3DSGraphObject. The common base (Q3DSNode) provides common properties like
the transformation (position, rotation, scale).
To change a property at runtime, first find out the correct name for the
property from the \l {Attribute Names}{Scene Object Attribute List}.
Then do either
\badcode
node->notifyPropertyChanges({ node->setPosition(QVector3D(1.0f, 0.5f, 3.0f)) });
\endcode
or
\badcode
Q3DSPropertyChangeList cl { Q3DSPropertyChange::fromVariant("position", QVector3D(1.0f, 0.5f, 3.0f) };
node->applyPropertyChanges(cl);
node->notifyPropertyChanges(cl);
\endcode
The former is more efficient, while the latter allows constructing change
lists dynamically with the property names given as strings instead of
having to call C++ setter functions.
To get access to an object, for example, the Q3DSModelNode corresponding to
a Model in the editor, use the Q3DSUipPresentation's object() or
objectByName() functions. The latter is more useful for applications since
it works based on the Name (that is defined by the designer in the editor),
while the former uses the object id that is unique, but invisible to the
designer in the editor.
\note Names do not have to be unique. This can cause confusion because some
names the editor assigns by default are shared between multiple objects. To
prevent this, rename the objects in the tree view to something unique.
\badcode
auto car = presentation->objectByName<Q3DSModelNode>(QLatin1String("FancySportsCar"));
\endcode
Besides changing properties, adding or removing objects at runtime is also
possible. This will lead to the corresponding graphics objects appearing or
disappearing. For example, to spawn a new model object with the built-in
cube as its mesh:
\badcode
Q3DSModelNode *cube = presentation->newObject<Q3DSModelNode>(QByteArrayLiteral("newCube"));
cube->setMesh(QLatin1String("#Cube"));
Q3DSDefaultMaterial *cubeMat = presentation->newObject<Q3DSDefaultMaterial>(QByteArrayLiteral("cubeMaterial"));
cube->appendChildNode(cubeMat);
group->appendChildNode(cube);
\endcode
appendChildNode() takes ownership and inserts the given object in the
parent's child list. This is similar to QObject::setParent() but note that
QSGNode and Q3DSGraphObject are more powerful since they allow not just
appending but also inserting at arbitrary positions in the child list.
When a newly created object gets added to a parent that itself is already
part of a hierarchy under a Q3DSScene, the object becomes active, which
triggers creating the graphics and 3D resources that are necessary to
render the object in the associated layer's texture. In the above example
this point is the last appendChildNode() call, assuming \c group is an
object already parented into a live Q3DSScene tree.
To properly disconnect an object from the scene, use
Q3DSUipPresentation::unlinkObject():
\badcode
presentation->unlinkObject(cube);
delete cube;
\endcode
Due to the unlinkObject() call, the cube will disappear from the screen.
Note that the Q3DSDefaultMaterial child object is unlinked and destroyed as
well, just like a child QObject is destroyed together with its parent.
Being part of the scenegraph is not enough to get displayed, however. The
concept of slides has a great effect on visibility as well. To associate a
newly created object with a slide, call Q3DSSlide::addObject(). For
example, assuming the \c{.uip} file loaded has one slide under the master
slide:
\badcode
Q3DSSlide *slide = static_cast<Q3DSSlide *>(presentation->masterSlide()->firstChild());
slide->addObject(cubeMat);
slide->addObject(cube);
\endcode
The children of the new object have to be managed manually here, hence the
separate addObject(cubeMat) call. It is not required that all descendants
of an object belong to the same slide as the object.
When removing objects, make sure to disconnect them from the slide as well.
To do this recursively for all objects in the subtree that is about to
removed, one can do the following:
\badcode
Q3DSUipPresentation::forAllObjectsInSubTree(cube, [slide](Q3DSGraphObject *obj) {
slide->removeObject(obj);
});
\endcode
There are many more possibilities with the Q3DSGraphObject API. Refer to
the header files for more insight. It is worth nothing that it is also
possible to build Qt 3D Studio scenes completely from C++, without using
any \c{.uip} files. Check the demo application under
\c{tests/manual/standalone} in the runtime's source tree for an example of
creating and managing interactive scenes this way. It is also a good
example for performing advanced tasks via the private API, like reacting on
input events, providing custom mesh data, and dynamically generating
texture maps.
*/
|