1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qlevelofdetail.h" |
41 | #include "qlevelofdetail_p.h" |
42 | #include "qcamera.h" |
43 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | namespace Qt3DRender { |
47 | |
48 | QLevelOfDetailPrivate::QLevelOfDetailPrivate() |
49 | : QComponentPrivate() |
50 | , m_camera(nullptr) |
51 | , m_currentIndex(0) |
52 | , m_thresholdType(QLevelOfDetail::DistanceToCameraThreshold) |
53 | , m_volumeOverride() |
54 | { |
55 | } |
56 | |
57 | void QLevelOfDetailPrivate::setCurrentIndex(int currentIndex) |
58 | { |
59 | Q_Q(QLevelOfDetail); |
60 | if (m_currentIndex != currentIndex) { |
61 | m_currentIndex = currentIndex; |
62 | emit q->currentIndexChanged(currentIndex: m_currentIndex); |
63 | } |
64 | } |
65 | |
66 | /*! |
67 | \class Qt3DRender::QLevelOfDetail |
68 | \inmodule Qt3DRender |
69 | \since 5.9 |
70 | \brief The QLevelOfDetail class provides a way of controlling the complexity |
71 | of rendered entities based on their size on the screen. |
72 | |
73 | QLevelOfDetail can be used to control the representation of an entity |
74 | based on distance from the observer or size on the screen. |
75 | |
76 | In order to improve rendering performance, objects that are very small |
77 | can be rendered using far fewer details, in geometry or texture. |
78 | |
79 | The component is controlled by specifying thresholds of values which are interpreted |
80 | as either distances from the camera or screen size. |
81 | |
82 | As the point of view changes, the currentIndex property will change to |
83 | reflect matching value in the range array. |
84 | |
85 | The currentIndex property can then be used, for example, to enable or |
86 | disable entities, change material, etc. |
87 | |
88 | The LevelOfDetail component is not shareable between multiple \l [QML]{Entity}{entities}. |
89 | |
90 | \code |
91 | #include <Qt3DCore/QEntity> |
92 | #include <Qt3DRender/QGeometryRenderer> |
93 | #include <Qt3DRender/QLevelOfDetail> |
94 | |
95 | // Scene |
96 | Qt3DCore::QEntity *rootEntity = new Qt3DCore::Qt3DCore::QEntity; |
97 | |
98 | Qt3DCore::QEntity *renderableEntity = new Qt3DCore::QEntity(rootEntity); |
99 | Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DCore::QGeometryRenderer(renderableEntity); |
100 | renderableEntity->addComponent(geometryRenderer); |
101 | Qt3DRender::QLevelOfDetail* lod = new Qt3Render::QLevelOfDetail(renderableEntity); |
102 | QVector<qreal> thresholds = {20, 35, 50, 65}; |
103 | lod->setThresholds(thresholds); |
104 | lod->setCamera(mainCamera); |
105 | renderableEntity->addComponent(lod); |
106 | |
107 | // connect to QLevelOfDetail::currentIndexChanged to toggle rendering |
108 | ... |
109 | \endcode |
110 | */ |
111 | |
112 | /*! |
113 | \qmltype LevelOfDetail |
114 | \instantiates Qt3DRender::QLevelOfDetail |
115 | \inherits Component3D |
116 | \inqmlmodule Qt3D.Render |
117 | \since 5.9 |
118 | \brief LevelOfDetail provides a way of controlling the complexity of |
119 | rendered entities based on their size on the screen. |
120 | |
121 | LevelOfDetail can be used to control the representation of an entity |
122 | based on distance from the observer or size on the screen. |
123 | |
124 | In order to improve rendering performance, objects that are very small |
125 | can be rendered using far fewer details, in geometry or texture. |
126 | |
127 | The component is controlled by specifying thresholds of values which are interpreted |
128 | as either distances from the camera or screen size. |
129 | |
130 | As the point of view changes, the currentIndex property will change to |
131 | reflect matching value in the range array. |
132 | |
133 | The currentIndex property can then be used, for example, to enable or |
134 | disable entities, change source in an EntityLoader, or material. |
135 | |
136 | The LevelOfDetail component is not shareable between multiple Entity's. |
137 | |
138 | \code |
139 | import Qt3D.Core 2.0 |
140 | import Qt3D.Render 2.0 |
141 | |
142 | Entity { |
143 | id: root |
144 | |
145 | // Scene |
146 | Camera { id: mainCamera } |
147 | |
148 | LevelOfDetail { |
149 | id: lod |
150 | camera: mainCamera |
151 | thresholds: [20, 35, 50, 65] |
152 | thresholdType: LevelOfDetail.DistanceToCameraThreshold |
153 | } |
154 | |
155 | CylinderMesh { |
156 | id: mesh |
157 | |
158 | property var sliceValues: [20, 10, 6, 4] |
159 | slices: sliceValues[lod.currentIndex] |
160 | } |
161 | |
162 | Entity { |
163 | id: renderableEntity |
164 | components: [ mesh, lod ] |
165 | } |
166 | } |
167 | \endcode |
168 | */ |
169 | |
170 | |
171 | /*! |
172 | * \enum Qt3DRender::QLevelOfDetail::ThresholdType |
173 | * |
174 | * Specifies how the values in the thresholds are interpreted |
175 | * |
176 | * \value DistanceToCameraThreshold Distance from the entity to the selected camera |
177 | * \value ProjectedScreenPixelSizeThreshold Size of the entity when projected on the |
178 | * screen as seen from the selected camera, expressed in number of |
179 | * pixels on the side of the bounding square in screen space. |
180 | */ |
181 | |
182 | /*! |
183 | * \qmlproperty enumeration LevelOfDetail::ThresholdType |
184 | * |
185 | * Specifies how the values in the thresholds are interpreted |
186 | * |
187 | * \list |
188 | * \li DistanceToCameraThreshold Distance from the entity to the selected camera |
189 | * \li ProjectedScreenPixelSizeThreshold Size of the entity when projected on the |
190 | * screen as seen from the selected camera, expressed in number of |
191 | * pixels on the side of the bounding square in screen space. |
192 | * \endlist |
193 | * \sa Qt3DRender::QLevelOfDetail::ThresholdType |
194 | */ |
195 | |
196 | /*! |
197 | * \qmlproperty Camera LevelOfDetail::camera |
198 | * |
199 | * Holds the id of the camera that is used to compute the actual distance or the screen size. |
200 | */ |
201 | |
202 | /*! |
203 | * \property QLevelOfDetail::camera |
204 | * |
205 | * Holds the id of the camera that is used to compute the actual distance or the screen size. |
206 | */ |
207 | |
208 | /*! |
209 | * \qmlproperty int LevelOfDetail::currentIndex |
210 | * |
211 | * The index in the range array which matches the current distance to the camera or screen size. |
212 | */ |
213 | |
214 | /*! |
215 | * \property QLevelOfDetail::currentIndex |
216 | * |
217 | * The index in the range array which matches the current distance to the camera or screen size. |
218 | */ |
219 | |
220 | /*! |
221 | * \qmlproperty int LevelOfDetail::thresholdType |
222 | * |
223 | * Specifies how range values are interpreted. |
224 | */ |
225 | |
226 | /*! |
227 | * \property QLevelOfDetail::thresholdType |
228 | * |
229 | * Specifies how range values are interpreted. |
230 | * \sa Qt3DRender::QLevelOfDetail::ThresholdType |
231 | */ |
232 | |
233 | /*! |
234 | * \qmlproperty QVector<qreal> LevelOfDetail::thresholds |
235 | * |
236 | * Array of range values as float point numbers. The value for the most detailed representation |
237 | * should be specified first. |
238 | * |
239 | * If LevelOfDetail::thresholdType is set to LevelOfDetail.DistanceToCameraThreshold, values should |
240 | * be specified in ascending order, in camera space coordinates |
241 | * |
242 | * If LevelOfDetail::thresholdType is set to LevelOfDetail.ProjectedScreenPixelSizeThreshold, values |
243 | * should be specified in descending order, in screen space pixels. |
244 | */ |
245 | |
246 | /*! |
247 | * \property QLevelOfDetail::thresholds |
248 | * |
249 | * Array of range values as float point numbers. The value for the most detailed representation |
250 | * should be specified first. |
251 | * |
252 | * If Qt3DRender::QLevelOfDetail::thresholdType is set to |
253 | * Qt3DRender::QLevelOfDetail::DistanceToCameraThreshold, values should be specified in |
254 | * ascending order, in camera space coordinates |
255 | * |
256 | * If Qt3DRender::QLevelOfDetail::thresholdType is set to |
257 | * Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSizeThreshold, values should |
258 | * be specified in descending order, in screen space pixels. |
259 | * |
260 | * \sa Qt3DRender::QLevelOfDetail::ThresholdType |
261 | */ |
262 | |
263 | /*! |
264 | * \qmlproperty int LevelOfDetail::volumeOverride |
265 | * |
266 | * Specifies what is used to evaluate the distance or screen size. |
267 | * |
268 | * The default is a sphere of radius 1 and centered at the local origin of the entity. |
269 | * This proxy volume is used to compute the distance to the camera or the size |
270 | * of the screen projection. |
271 | * |
272 | * If this value to null, the bounding volume of the entity is used. Care must be |
273 | * taken that this bounding volume never becomes invalid. |
274 | * |
275 | * \sa Qt3DRender::QLevelOfDetailBoundingSphere |
276 | */ |
277 | |
278 | /*! |
279 | * \property QLevelOfDetail::volumeOverride |
280 | * |
281 | * The default is a sphere of radius 1 and centered at the local origin of the entity. |
282 | * This proxy volume is used to compute the distance to the camera or the size |
283 | * of the screen projection. |
284 | * |
285 | * If this value to nullptr, the bounding volume of the entity is used. Care must be |
286 | * taken that this bounding volume never becomes invalid. |
287 | * |
288 | * \sa Qt3DRender::QLevelOfDetailBoundingSphere |
289 | */ |
290 | |
291 | |
292 | /*! \fn Qt3DRender::QLevelOfDetail::QLevelOfDetail(Qt3DCore::QNode *parent) |
293 | Constructs a new QLevelOfDetail with the specified \a parent. |
294 | */ |
295 | QLevelOfDetail::QLevelOfDetail(QNode *parent) |
296 | : QComponent(*new QLevelOfDetailPrivate, parent) |
297 | { |
298 | } |
299 | |
300 | /*! \internal */ |
301 | QLevelOfDetail::~QLevelOfDetail() |
302 | { |
303 | } |
304 | |
305 | /*! \internal */ |
306 | QLevelOfDetail::QLevelOfDetail(QLevelOfDetailPrivate &dd, QNode *parent) |
307 | : QComponent(dd, parent) |
308 | { |
309 | } |
310 | |
311 | /*! \internal */ |
312 | Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() const |
313 | { |
314 | auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QLevelOfDetailData>::create(arguments: this); |
315 | auto &data = creationChange->data; |
316 | |
317 | Q_D(const QLevelOfDetail); |
318 | if (d->m_camera) |
319 | data.camera = d->m_camera->id(); |
320 | data.currentIndex = d->m_currentIndex; |
321 | data.thresholdType = d->m_thresholdType; |
322 | data.thresholds = d->m_thresholds; |
323 | data.volumeOverride = d->m_volumeOverride; |
324 | |
325 | return creationChange; |
326 | } |
327 | |
328 | // TODO Unused remove in Qt6 |
329 | void QLevelOfDetail::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &) |
330 | { |
331 | } |
332 | |
333 | QCamera *QLevelOfDetail::camera() const |
334 | { |
335 | Q_D(const QLevelOfDetail); |
336 | return d->m_camera; |
337 | } |
338 | |
339 | /*! |
340 | * Sets the \a camera relative to which distance and size are computed. |
341 | */ |
342 | void QLevelOfDetail::setCamera(QCamera *camera) |
343 | { |
344 | Q_D(QLevelOfDetail); |
345 | if (d->m_camera != camera) { |
346 | d->m_camera = camera; |
347 | emit cameraChanged(camera: d->m_camera); |
348 | } |
349 | } |
350 | |
351 | int QLevelOfDetail::currentIndex() const |
352 | { |
353 | Q_D(const QLevelOfDetail); |
354 | return d->m_currentIndex; |
355 | } |
356 | |
357 | /*! |
358 | * Sets the \a currentIndex. |
359 | * |
360 | * \note This should not normally be set by the user. |
361 | * |
362 | * However, if the component is disabled, then changing the |
363 | * current index is a simple way of switching between multiple |
364 | * representations. |
365 | */ |
366 | void QLevelOfDetail::setCurrentIndex(int currentIndex) |
367 | { |
368 | Q_D(QLevelOfDetail); |
369 | d->setCurrentIndex(currentIndex); |
370 | } |
371 | |
372 | QLevelOfDetail::ThresholdType QLevelOfDetail::thresholdType() const |
373 | { |
374 | Q_D(const QLevelOfDetail); |
375 | return d->m_thresholdType; |
376 | } |
377 | |
378 | /*! |
379 | * Sets the way thresholds values are interpreted |
380 | * with parameter \a thresholdType |
381 | * \sa Qt3DRender::QLevelOfDetail::ThresholdType |
382 | */ |
383 | void QLevelOfDetail::setThresholdType(QLevelOfDetail::ThresholdType thresholdType) |
384 | { |
385 | Q_D(QLevelOfDetail); |
386 | if (d->m_thresholdType != thresholdType) { |
387 | d->m_thresholdType = thresholdType; |
388 | emit thresholdTypeChanged(thresholdType: d->m_thresholdType); |
389 | } |
390 | } |
391 | |
392 | QVector<qreal> QLevelOfDetail::thresholds() const |
393 | { |
394 | Q_D(const QLevelOfDetail); |
395 | return d->m_thresholds; |
396 | } |
397 | |
398 | QLevelOfDetailBoundingSphere QLevelOfDetail::createBoundingSphere(const QVector3D ¢er, float radius) |
399 | { |
400 | return QLevelOfDetailBoundingSphere(center, radius); |
401 | } |
402 | |
403 | /*! |
404 | * Sets the range values in \a thresholds. |
405 | * \sa Qt3DRender::QLevelOfDetail::thresholdType |
406 | */ |
407 | void QLevelOfDetail::setThresholds(const QVector<qreal> &thresholds) |
408 | { |
409 | Q_D(QLevelOfDetail); |
410 | if (d->m_thresholds != thresholds) { |
411 | d->m_thresholds = thresholds; |
412 | emit thresholdsChanged(thresholds: d->m_thresholds); |
413 | } |
414 | } |
415 | |
416 | QLevelOfDetailBoundingSphere QLevelOfDetail::volumeOverride() const |
417 | { |
418 | Q_D(const QLevelOfDetail); |
419 | return d->m_volumeOverride; |
420 | } |
421 | |
422 | void QLevelOfDetail::setVolumeOverride(const QLevelOfDetailBoundingSphere &volumeOverride) |
423 | { |
424 | Q_D(QLevelOfDetail); |
425 | if (d->m_volumeOverride != volumeOverride) { |
426 | d->m_volumeOverride = volumeOverride; |
427 | emit volumeOverrideChanged(volumeOverride); |
428 | } |
429 | } |
430 | |
431 | } // namespace Qt3DRender |
432 | |
433 | QT_END_NAMESPACE |
434 | |
435 | #include "moc_qlevelofdetail.cpp" |
436 | |