21#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
22#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
24#include <QtQuick3DUtils/private/qssgassert_p.h>
25#include <QtQuick3DUtils/private/qssgfrustum_p.h>
27#include <qsgtextureprovider.h>
28#include <QSGSimpleTextureNode>
29#include <QSGRendererInterface>
30#include <QQuickWindow>
31#include <QtQuick/private/qquickitem_p.h>
32#include <QtQuick/private/qquickpointerhandler_p.h>
36#include <QtGui/private/qeventpoint_p.h>
38#include <QtCore/private/qnumeric_p.h>
39#include <QtCore/qpointer.h>
45Q_STATIC_LOGGING_CATEGORY(lcEv,
"qt.quick3d.event")
46Q_STATIC_LOGGING_CATEGORY(lcPick,
"qt.quick3d.pick")
48static bool isforceInputHandlingSet()
50 static const bool v = (qEnvironmentVariableIntValue(
"QT_QUICK3D_FORCE_INPUT_HANDLING") > 0);
57 for (
const auto &o : std::as_const(owners)) {
59 o->setSceneTransform(
nullptr);
65 da->setSceneTransform(
this);
70
71
72
73
74
76 QPointF point = viewportPoint;
81 point = viewport->mapFromScene(viewportPoint);
84 std::optional<QSSGRenderRay> rayResult =
renderer->getRayFromViewportPos(point);
85 if (rayResult.has_value()) {
87 if (!pickResults.isEmpty()) {
88 const auto pickResult = pickResults.first();
89 auto ret = pickResult.m_localUVCoords.toPointF();
91 ret = QPointF(targetItem->x() + ret.x() * targetItem->width(),
92 targetItem->y() - ret.y() * targetItem->height() + targetItem->height());
94 const bool outOfModel = pickResult.m_localUVCoords.isNull();
95 qCDebug(lcEv) << viewportPoint <<
"->" << (outOfModel ?
"OOM" :
"") << ret <<
"@" << pickResult.m_scenePosition
96 <<
"UV" << pickResult.m_localUVCoords <<
"dist" << qSqrt(pickResult.m_distanceSq);
98 return lastGoodMapping;
100 lastGoodMapping = ret;
126 static void extensionAppend(QQmlListProperty<QQuick3DObject> *list, QQuick3DObject *extension)
128 QSSG_ASSERT(list && extension,
return);
130 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
131 if (
const auto idx = that->m_extensions.indexOf(extension); idx == -1) {
132 if (!extension->parentItem())
133 extension->setParentItem(that->m_sceneRoot);
134 that->m_extensions.push_back(extension);
135 that->m_extensionListDirty =
true;
141 QQuick3DObject *ret =
nullptr;
142 QSSG_ASSERT(list,
return ret);
144 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
145 if (that->m_extensions.size() > index)
146 ret = that->m_extensions.at(index);
154 QSSG_ASSERT(list,
return ret);
156 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object))
157 ret = that->m_extensions.size();
163 QSSG_ASSERT(list,
return);
165 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
166 that->m_extensions.clear();
167 that->m_extensionListDirty =
true;
170 static void extensionReplace(QQmlListProperty<QQuick3DObject> *list, qsizetype idx, QQuick3DObject *o)
172 QSSG_ASSERT(list,
return);
174 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
175 if (that->m_extensions.size() > idx && idx > -1) {
176 that->m_extensions.replace(idx, o);
177 that->m_extensionListDirty =
true;
183 QSSG_ASSERT(list,
return);
185 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
186 that->m_extensions.removeLast();
187 that->m_extensionListDirty =
true;
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
246QQuick3DViewport::QQuick3DViewport(QQuickItem *parent)
249 setFlag(ItemHasContents);
251 m_sceneRoot =
new QQuick3DSceneRootNode(
this);
252 m_renderStats =
new QQuick3DRenderStats();
253 QQuick3DSceneManager *sceneManager =
new QQuick3DSceneManager();
254 QQuick3DObjectPrivate::get(m_sceneRoot)->refSceneManager(*sceneManager);
255 Q_ASSERT(sceneManager == QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager);
256 connect(sceneManager, &QQuick3DSceneManager::needsUpdate,
257 this, &QQuickItem::update);
261 if (isforceInputHandlingSet()) {
262 m_enableInputProcessing =
true;
263 updateInputProcessing();
268QQuick3DViewport::~QQuick3DViewport()
277 if (m_directRenderer && m_directRenderer->thread() == thread()) {
278 delete m_directRenderer;
279 m_directRenderer =
nullptr;
284 if (
auto qw = window())
285 disconnect(qw,
nullptr,
this,
nullptr);
287 auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
289 sceneManager->setParent(
nullptr);
290 if (
auto wa = sceneManager->wattached)
291 wa->queueForCleanup(sceneManager);
295 m_sceneRoot =
nullptr;
297 delete m_builtInEnvironment;
301 m_renderStats->deleteLater();
303 if (!window() && sceneManager && sceneManager->wattached)
304 QMetaObject::invokeMethod(sceneManager->wattached, &QQuick3DWindowAttachment::evaluateEol, Qt::QueuedConnection);
307static void ssgn_append(QQmlListProperty<QObject> *property, QObject *obj)
311 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
313 if (QQuick3DObject *sceneObject = qmlobject_cast<QQuick3DObject *>(obj)) {
314 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
315 itemProperty.append(&itemProperty, sceneObject);
317 QQuickItemPrivate::data_append(property, obj);
323 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
324 if (!view3d || !view3d->scene() || !QQuick3DObjectPrivate::get(view3d->scene())->data().count)
326 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
327 return itemProperty.count(&itemProperty);
332 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
333 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
334 return itemProperty.at(&itemProperty, i);
339 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
340 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
341 return itemProperty.clear(&itemProperty);
345QQmlListProperty<QObject> QQuick3DViewport::data()
347 return QQmlListProperty<QObject>(
this,
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372QQuick3DCamera *QQuick3DViewport::camera()
const
378
379
380
381
382
383
384
385
386QQuick3DSceneEnvironment *QQuick3DViewport::environment()
const
388 if (!m_environment) {
389 if (!m_builtInEnvironment) {
390 m_builtInEnvironment =
new QQuick3DSceneEnvironment;
394 if (QThread::currentThread() != m_sceneRoot->thread())
395 m_builtInEnvironment->moveToThread(m_sceneRoot->thread());
396 m_builtInEnvironment->setParentItem(m_sceneRoot);
399 return m_builtInEnvironment;
402 return m_environment;
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425QQuick3DNode *QQuick3DViewport::scene()
const
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457QQuick3DNode *QQuick3DViewport::importScene()
const
459 return m_importScene;
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505QQuick3DViewport::RenderMode QQuick3DViewport::renderMode()
const
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531#if QT_CONFIG(quick_shadereffect)
532QQuickShaderEffectSource::Format QQuick3DViewport::renderFormat()
const
534 return m_renderFormat;
539
540
541
542
543
544
545
546
547QQuick3DRenderStats *QQuick3DViewport::renderStats()
const
549 return m_renderStats;
552QQuick3DSceneRenderer *QQuick3DViewport::createRenderer()
const
554 QQuick3DSceneRenderer *renderer =
nullptr;
556 if (QQuickWindow *qw = window()) {
557 auto wa = QQuick3DSceneManager::getOrSetWindowAttachment(*qw);
558 auto rci = wa->rci();
560 QSGRendererInterface *rif = qw->rendererInterface();
561 if (QSSG_GUARD(QSGRendererInterface::isApiRhiBased(rif->graphicsApi()))) {
562 QRhi *rhi =
static_cast<QRhi *>(rif->getResource(qw, QSGRendererInterface::RhiResource));
563 QSSG_CHECK_X(rhi !=
nullptr,
"No QRhi from QQuickWindow, this cannot happen");
573 rci = std::make_shared<QSSGRenderContextInterface>(rhi);
577 connect(wa, &QQuick3DWindowAttachment::releaseCachedResources,
this,
578 &QQuick3DViewport::onReleaseCachedResources, Qt::DirectConnection);
581 qWarning(
"The Qt Quick scene is using a rendering method that is not based on QRhi and a 3D graphics API. "
582 "Qt Quick 3D is not functional in such an environment. The View3D item is not going to display anything.");
587 renderer =
new QQuick3DSceneRenderer(rci);
588 Q_QUICK3D_PROFILE_ASSIGN_ID(
this, renderer);
595bool QQuick3DViewport::isTextureProvider()
const
598 if (m_renderMode == QQuick3DViewport::Offscreen)
604QSGTextureProvider *QQuick3DViewport::textureProvider()
const
609 if (QQuickItem::isTextureProvider())
610 return QQuickItem::textureProvider();
613 if (m_renderMode != QQuick3DViewport::Offscreen)
616 QQuickWindow *w = window();
618 qWarning(
"QSSGView3D::textureProvider: can only be queried on the rendering thread of an exposed window");
623 m_node =
new SGFramebufferObjectNode;
636void QQuick3DViewport::releaseResources()
638 if (m_directRenderer) {
639 window()->scheduleRenderJob(
new CleanupJob(m_directRenderer), QQuickWindow::BeforeSynchronizingStage);
640 m_directRenderer =
nullptr;
646void QQuick3DViewport::cleanupDirectRenderer()
648 delete m_directRenderer;
649 m_directRenderer =
nullptr;
652void QQuick3DViewport::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
654 QQuickItem::geometryChange(newGeometry, oldGeometry);
656 if (newGeometry.size() != oldGeometry.size())
660QSGNode *QQuick3DViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
663 if (m_renderModeDirty) {
668 m_renderNode =
nullptr;
670 if (m_directRenderer) {
671 delete m_directRenderer;
672 m_directRenderer =
nullptr;
676 m_renderModeDirty =
false;
678 switch (m_renderMode) {
683 setupDirectRenderer(m_renderMode);
687 node = setupOffscreenRenderer(node);
691 node = setupInlineRenderer(node);
695 if (!isforceInputHandlingSet()) {
697 const auto inputHandlingEnabled =
698 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->inputHandlingEnabled;
699 const auto enable = inputHandlingEnabled > 0;
700 if (m_enableInputProcessing != enable) {
701 m_enableInputProcessing = enable;
702 QMetaObject::invokeMethod(
this,
"updateInputProcessing", Qt::QueuedConnection);
709void QQuick3DViewport::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
711 if (change == ItemSceneChange) {
715 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->setWindow(value.window);
717 QQuick3DObjectPrivate::get(m_importScene)->sceneManager->setWindow(value.window);
718 m_renderStats->setWindow(value.window);
720 }
else if (change == ItemVisibleHasChanged && isVisible()) {
721 m_visibilityChanged =
true;
726bool QQuick3DViewport::event(QEvent *event)
728 if (m_enableInputProcessing && event->isPointerEvent())
729 return internalPick(
static_cast<QPointerEvent *>(event));
731 return QQuickItem::event(event);
734void QQuick3DViewport::componentComplete()
736 QQuickItem::componentComplete();
737 Q_QUICK3D_PROFILE_REGISTER(
this);
740void QQuick3DViewport::setCamera(QQuick3DCamera *camera)
742 if (m_camera == camera)
745 if (camera && !camera->parentItem())
746 camera->setParentItem(m_sceneRoot);
748 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
750 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setCamera, camera, m_camera);
753 emit cameraChanged();
757void QQuick3DViewport::setMultiViewCameras(QQuick3DCamera **firstCamera,
int count)
759 m_multiViewCameras.clear();
760 bool sendChangeSignal =
false;
761 for (
int i = 0; i < count; ++i) {
762 QQuick3DCamera *camera = *(firstCamera + i);
764 if (!camera->parentItem())
765 camera->setParentItem(m_sceneRoot);
766 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
769 if (m_camera != camera) {
771 sendChangeSignal =
true;
775 m_multiViewCameras.append(camera);
780 if (sendChangeSignal)
781 emit cameraChanged();
786void QQuick3DViewport::setEnvironment(QQuick3DSceneEnvironment *environment)
788 if (m_environment == environment)
791 m_environment = environment;
792 if (m_environment && !m_environment->parentItem())
793 m_environment->setParentItem(m_sceneRoot);
795 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setEnvironment, environment, m_environment);
797 emit environmentChanged();
801void QQuick3DViewport::setImportScene(QQuick3DNode *inScene)
811 QQuick3DNode *scene = inScene;
813 if (m_sceneRoot == scene) {
814 qmlWarning(
this) <<
"Cannot allow self-import or cross-import!";
818 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
819 scene = rn ? rn->view3D()->importScene() :
nullptr;
822 m_importScene = inScene;
824 updateSceneManagerForImportScene();
826 emit importSceneChanged();
830void QQuick3DViewport::setRenderMode(QQuick3DViewport::RenderMode renderMode)
832 if (m_renderMode == renderMode)
835 m_renderMode = renderMode;
836 m_renderModeDirty =
true;
837 emit renderModeChanged();
841#if QT_CONFIG(quick_shadereffect)
842void QQuick3DViewport::setRenderFormat(QQuickShaderEffectSource::Format format)
844 if (m_renderFormat == format)
847 m_renderFormat = format;
848 m_renderModeDirty =
true;
849 emit renderFormatChanged();
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873int QQuick3DViewport::explicitTextureWidth()
const
875 return m_explicitTextureWidth;
878void QQuick3DViewport::setExplicitTextureWidth(
int width)
880 if (m_explicitTextureWidth == width)
883 m_explicitTextureWidth = width;
884 emit explicitTextureWidthChanged();
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907int QQuick3DViewport::explicitTextureHeight()
const
909 return m_explicitTextureHeight;
912void QQuick3DViewport::setExplicitTextureHeight(
int height)
914 if (m_explicitTextureHeight == height)
917 m_explicitTextureHeight = height;
918 emit explicitTextureHeightChanged();
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937QSize QQuick3DViewport::effectiveTextureSize()
const
939 return m_effectiveTextureSize;
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959QVector3D QQuick3DViewport::mapFrom3DScene(
const QVector3D &scenePos)
const
962 qmlWarning(
this) <<
"Cannot resolve view position without a camera assigned!";
963 return QVector3D(0, 0, 0);
966 qreal _width = width();
967 qreal _height = height();
968 if (_width == 0 || _height == 0)
969 return QVector3D(0, 0, 0);
971 const QVector3D normalizedPos = m_camera->mapToViewport(scenePos, _width, _height);
972 return normalizedPos * QVector3D(
float(_width),
float(_height), 1);
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992QVector3D QQuick3DViewport::mapTo3DScene(
const QVector3D &viewPos)
const
995 qmlWarning(
this) <<
"Cannot resolve scene position without a camera assigned!";
996 return QVector3D(0, 0, 0);
999 qreal _width = width();
1000 qreal _height = height();
1001 if (_width == 0 || _height == 0)
1002 return QVector3D(0, 0, 0);
1004 const QVector3D normalizedPos = viewPos / QVector3D(
float(_width),
float(_height), 1);
1005 return m_camera->mapFromViewport(normalizedPos, _width, _height);
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y)
const
1024 QQuick3DSceneRenderer *renderer = getRenderer();
1026 return QQuick3DPickResult();
1028 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1029 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1030 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1031 if (!rayResult.has_value())
1032 return QQuick3DPickResult();
1034 const auto resultList = renderer->syncPick(rayResult.value());
1035 return getNearestPickResult(resultList);
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y, QQuick3DModel *model)
const
1052 QQuick3DSceneRenderer *renderer = getRenderer();
1054 return QQuick3DPickResult();
1056 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1057 qreal(y) * window()->effectiveDevicePixelRatio());
1058 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1060 if (!rayResult.has_value())
1061 return QQuick3DPickResult();
1063 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1064 const auto resultList = renderer->syncPickOne(rayResult.value(), renderNode);
1065 return getNearestPickResult(resultList);
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085QList<QQuick3DPickResult> QQuick3DViewport::pickSubset(
float x,
float y,
const QJSValue &models)
const
1087 QQuick3DSceneRenderer *renderer = getRenderer();
1091 QVarLengthArray<QSSGRenderNode*> renderNodes;
1093 if (models.isArray()) {
1094 const auto length = models.property(QStringLiteral(
"length")).toInt();
1098 for (
int i = 0; i < length; ++i) {
1099 const auto isQObject = models.property(i).isQObject();
1101 qmlWarning(
this) <<
"Type provided for picking is not a QObject. Needs to be of type QQuick3DModel.";
1104 const auto obj = models.property(i).toQObject();
1105 const auto model = qobject_cast<QQuick3DModel *>(obj);
1107 qmlWarning(
this) <<
"Type " << obj->metaObject()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1110 const auto priv = QQuick3DObjectPrivate::get(model);
1111 if (priv && priv->spatialNode) {
1112 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1117 const auto subsetVariant = models.toVariant();
1118 if (!subsetVariant.isValid() || !subsetVariant.canConvert<QQmlListReference>())
1121 const auto list = subsetVariant.value<QQmlListReference>();
1124 if (list.listElementType()->className() != QQuick3DModel::staticMetaObject.className()) {
1125 qmlWarning(
this) <<
"Type " << list.listElementType()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1128 for (
int i = 0; i < list.count(); ++i) {
1129 auto model =
static_cast<QQuick3DModel *>(list.at(i));
1132 auto priv = QQuick3DObjectPrivate::get(model);
1133 if (priv && priv->spatialNode) {
1134 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1139 if (renderNodes.empty())
1142 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1143 qreal(y) * window()->effectiveDevicePixelRatio());
1144 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1145 if (!rayResult.has_value())
1148 const auto resultList = renderer->syncPickSubset(rayResult.value(), renderNodes);
1150 QList<QQuick3DPickResult> processedResultList;
1151 processedResultList.reserve(resultList.size());
1152 for (
const auto &result : resultList)
1153 processedResultList.append(processPickResult(result));
1155 return processedResultList;
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172QList<QQuick3DPickResult> QQuick3DViewport::pickAll(
float x,
float y)
const
1174 QQuick3DSceneRenderer *renderer = getRenderer();
1176 return QList<QQuick3DPickResult>();
1178 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1179 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1180 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1181 if (!rayResult.has_value())
1182 return QList<QQuick3DPickResult>();
1184 const auto resultList = renderer->syncPickAll(rayResult.value());
1185 QList<QQuick3DPickResult> processedResultList;
1186 processedResultList.reserve(resultList.size());
1187 for (
const auto &result : resultList)
1188 processedResultList.append(processPickResult(result));
1190 return processedResultList;
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction)
const
1212 QQuick3DSceneRenderer *renderer = getRenderer();
1214 return QQuick3DPickResult();
1216 const QSSGRenderRay ray(origin, direction);
1217 const auto resultList = renderer->syncPick(ray);
1218 return getNearestPickResult(resultList);
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237QList<QQuick3DPickResult> QQuick3DViewport::rayPickAll(
const QVector3D &origin,
const QVector3D &direction)
const
1239 QQuick3DSceneRenderer *renderer = getRenderer();
1241 return QList<QQuick3DPickResult>();
1243 const QSSGRenderRay ray(origin, direction);
1245 const auto resultList = renderer->syncPickAll(ray);
1246 QList<QQuick3DPickResult> processedResultList;
1247 processedResultList.reserve(resultList.size());
1248 for (
const auto &result : resultList) {
1249 auto processedResult = processPickResult(result);
1250 if (processedResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1251 processedResultList.append(processedResult);
1254 return processedResultList;
1258
1259
1260
1261
1262
1263
1264
1265QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction, QQuick3DModel *model)
const
1267 QQuick3DSceneRenderer *renderer = getRenderer();
1269 return QQuick3DPickResult();
1271 const QSSGRenderRay ray(origin, direction);
1273 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1274 const auto resultList = renderer->syncPickOne(ray, renderNode);
1275 return getNearestPickResult(resultList);
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288QQuick3DPickResult QQuick3DViewport::closestPointPick(
const QVector3D &origin,
float radius, QQuick3DModel *model)
const
1290 QQuick3DSceneRenderer *renderer = getRenderer();
1293 return QQuick3DPickResult();
1294 QSSGRenderNode *renderNode =
nullptr;
1296 renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1297 if (Q_UNLIKELY(!renderNode))
1298 return QQuick3DPickResult{};
1301 const auto pickResult = renderer->syncPickClosestPoint(origin, radius * radius, renderNode);
1302 if (!pickResult.has_value())
1303 return QQuick3DPickResult{};
1304 return processPickResult(pickResult.value());
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320QList<QQuick3DObject *> QQuick3DViewport::pickInRect(
const QPointF &start,
const QPointF &end)
const
1322 const qreal minX = qMin(start.x(), end.x());
1323 const qreal maxX = qMax(start.x(), end.x());
1324 const qreal minY = qMin(start.y(), end.y());
1325 const qreal maxY = qMax(start.y(), end.y());
1327 const qreal ndc[4] = {
1328 2.0f * minX / width() - 1.0f,
1329 2.0f * maxX / width() - 1.0f,
1331 1.0f - 2.0f * maxY / height(),
1332 1.0f - 2.0f * minY / height(),
1335 const float near = 0.0f;
1336 const float far = 1.0f;
1337 enum { L, R, B, T };
1338 const QVector4D ndcCorners[8] = {
1340 QVector4D(ndc[L], ndc[B], near, 1.0f),
1341 QVector4D(ndc[R], ndc[B], near, 1.0f),
1342 QVector4D(ndc[L], ndc[T], near, 1.0f),
1343 QVector4D(ndc[R], ndc[T], near, 1.0f),
1345 QVector4D(ndc[L], ndc[B], far, 1.0f),
1346 QVector4D(ndc[R], ndc[B], far, 1.0f),
1347 QVector4D(ndc[L], ndc[T], far, 1.0f),
1348 QVector4D(ndc[R], ndc[T], far, 1.0f),
1351 QMatrix4x4 viewProjection;
1352 if (
this->camera()) {
1353 if (
auto camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this->camera())->spatialNode))
1354 camera->calculateViewProjectionMatrix(camera->localTransform, camera->projection, viewProjection);
1356 QMatrix4x4 viewProjectionInverted = viewProjection.inverted();
1358 QVector3D worldCorners[8];
1359 for (
int i = 0; i < 8; ++i) {
1360 QVector4D worldPoint = viewProjectionInverted * ndcCorners[i];
1361 worldCorners[i] = worldPoint.toVector3D() / worldPoint.w();
1380 const QSSGFrustum frustum {
1381 QSSGPlane(worldCorners[0], worldCorners[4], worldCorners[6]),
1382 QSSGPlane(worldCorners[1], worldCorners[3], worldCorners[7]),
1383 QSSGPlane(worldCorners[0], worldCorners[1], worldCorners[5]),
1384 QSSGPlane(worldCorners[2], worldCorners[6], worldCorners[7]),
1385 QSSGPlane(worldCorners[0], worldCorners[2], worldCorners[3]),
1386 QSSGPlane(worldCorners[5], worldCorners[7], worldCorners[6]),
1389 QList<QQuick3DObject *> ret;
1390 if (QQuick3DSceneRenderer *renderer = getRenderer()) {
1391 auto nodes = renderer->syncPickInFrustum(frustum);
1392 for (
const auto *node : std::as_const(nodes)) {
1393 if (QQuick3DObject *m = findFrontendNode(node))
1401void QQuick3DViewport::processPointerEventFromRay(
const QVector3D &origin,
const QVector3D &direction, QPointerEvent *event)
const
1403 internalPick(event, origin, direction);
1410class SyntheticTouchDevice :
public QPointingDevice
1413 SyntheticTouchDevice(QObject *parent =
nullptr)
1414 : QPointingDevice(QLatin1StringView(
"QtQuick3D Touch Synthesizer"),
1416 DeviceType::TouchScreen,
1417 PointerType::Finger,
1418 Capability::Position,
1420 QString(), QPointingDeviceUniqueId(),
1428
1429
1430
1431
1432
1433
1434
1435
1436
1438void QQuick3DViewport::setTouchpoint(QQuickItem *target,
const QPointF &position,
int pointId,
bool pressed)
1440 if (pointId >= m_touchState.size())
1441 m_touchState.resize(pointId + 1);
1442 auto prevState = m_touchState[pointId];
1444 const bool sameTarget = prevState.target == target;
1445 const bool wasPressed = prevState.isPressed;
1447 const bool isPress = pressed && (!sameTarget || !wasPressed);
1448 const bool isRelease = !pressed && wasPressed && sameTarget;
1453 if (!sameTarget && wasPressed)
1454 qWarning(
"QQuick3DViewport::setTouchpoint missing release event");
1456 if (!pressed && !wasPressed) {
1461 m_touchState[pointId] = { target, position, pressed };
1463 if (!m_syntheticTouchDevice)
1464 m_syntheticTouchDevice =
new SyntheticTouchDevice(
this);
1466 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(m_syntheticTouchDevice);
1468 auto makePoint = [devPriv](
int id, QEventPoint::State pointState, QPointF pos, quint64 timestamp) -> QEventPoint {
1469 auto epd = devPriv->pointById(id);
1470 auto &ep = epd->eventPoint;
1471 if (pointState != QEventPoint::State::Stationary)
1472 ep.setAccepted(
false);
1474 auto res = QMutableEventPoint::withTimeStamp(timestamp, id, pointState, pos, pos, pos);
1475 QMutableEventPoint::update(res, ep);
1477 if (pointState == QEventPoint::State::Pressed)
1478 QMutableEventPoint::setGlobalPressPosition(res, pos);
1479 else if (ep.state() != QEventPoint::State::Unknown)
1480 QMutableEventPoint::setGlobalPressPosition(res, ep.globalPressPosition());
1485 auto sendTouchEvent = [&](QQuickItem *t,
const QPointF &position,
int pointId, QEventPoint::State pointState, quint64 timestamp) ->
void {
1486 QList<QEventPoint> points;
1487 bool otherPoint =
false;
1488 for (
int i = 0; i < m_touchState.size(); ++i) {
1489 const auto &ts = m_touchState[i];
1493 auto newPoint = makePoint(i, pointState, position, timestamp);
1495 }
else if (ts.isPressed) {
1497 points << makePoint(i, QEventPoint::Stationary, ts.position, timestamp);
1502 if (pointState == QEventPoint::Pressed && !otherPoint)
1503 type = QEvent::Type::TouchBegin;
1504 else if (pointState == QEventPoint::Released && !otherPoint)
1505 type = QEvent::Type::TouchEnd;
1507 type = QEvent::Type::TouchUpdate;
1509 QTouchEvent ev(type, m_syntheticTouchDevice, {}, points);
1510 ev.setTimestamp(timestamp);
1514 auto da = QQuickItemPrivate::get(t)->deliveryAgent();
1515 bool handled = da->event(&ev);
1520 if (ev.isEndEvent()) {
1521 for (
auto &point : ev.points()) {
1522 if (point.state() == QEventPoint::State::Released) {
1523 ev.setExclusiveGrabber(point,
nullptr);
1524 ev.clearPassiveGrabbers(point);
1530 auto timestamp = QDateTime::currentMSecsSinceEpoch();
1533 if (prevState.target && !sameTarget)
1534 sendTouchEvent(prevState.target, prevState.position, pointId, QEventPoint::Released, timestamp);
1537 QEventPoint::State newState = isPress ? QEventPoint::Pressed : isRelease ? QEventPoint::Released : QEventPoint::Updated;
1538 sendTouchEvent(target, position, pointId, newState, timestamp);
1541QQuick3DLightmapBaker *QQuick3DViewport::maybeLightmapBaker()
1543 return m_lightmapBaker;
1546QQuick3DLightmapBaker *QQuick3DViewport::lightmapBaker()
1548 if (!m_lightmapBaker)
1549 m_lightmapBaker=
new QQuick3DLightmapBaker(
this);
1551 return m_lightmapBaker;
1555
1556
1557void QQuick3DViewport::bakeLightmap()
1559 QQuick3DSceneRenderer *renderer = getRenderer();
1560 if (!renderer || !renderer->m_layer->renderData)
1563 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1565 if (!currentlyBaking)
1566 lightmapBaker()->bake();
1570
1571
1572void QQuick3DViewport::denoiseLightmap()
1574 QQuick3DSceneRenderer *renderer = getRenderer();
1575 if (!renderer || !renderer->m_layer->renderData)
1578 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1580 if (!currentlyBaking)
1581 lightmapBaker()->denoise();
1585void QQuick3DViewport::setGlobalPickingEnabled(
bool isEnabled)
1587 QQuick3DSceneRenderer *renderer = getRenderer();
1591 renderer->setGlobalPickingEnabled(isEnabled);
1594void QQuick3DViewport::invalidateSceneGraph()
1597 m_renderNode =
nullptr;
1600QQuick3DSceneRenderer *QQuick3DViewport::getRenderer()
const
1602 QQuick3DSceneRenderer *renderer =
nullptr;
1604 renderer = m_node->renderer;
1605 }
else if (m_renderNode) {
1606 renderer = m_renderNode->renderer;
1607 }
else if (m_directRenderer) {
1608 renderer = m_directRenderer->renderer();
1613void QQuick3DViewport::updateDynamicTextures()
1618 const auto &sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
1619 for (
auto *texture : std::as_const(sceneManager->qsgDynamicTextures))
1620 texture->updateTexture();
1622 QQuick3DNode *scene = m_importScene;
1624 const auto &importSm = QQuick3DObjectPrivate::get(scene)->sceneManager;
1625 if (importSm != sceneManager) {
1626 for (
auto *texture : std::as_const(importSm->qsgDynamicTextures))
1627 texture->updateTexture();
1631 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
1632 scene = rn ? rn->view3D()->importScene() :
nullptr;
1636QSGNode *QQuick3DViewport::setupOffscreenRenderer(QSGNode *node)
1638 SGFramebufferObjectNode *n =
static_cast<SGFramebufferObjectNode *>(node);
1642 m_node =
new SGFramebufferObjectNode;
1647 n->window = window();
1648 n->renderer = createRenderer();
1651 n->renderer->fboNode = n;
1653 connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
1656 const qreal dpr = window()->effectiveDevicePixelRatio();
1657 const QSize minFboSize = QQuickItemPrivate::get(
this)->sceneGraphContext()->minimumFBOSize();
1658 QSize desiredFboSize = QSize(m_explicitTextureWidth, m_explicitTextureHeight);
1659 if (desiredFboSize.isEmpty()) {
1660 desiredFboSize = QSize(width(), height()) * dpr;
1661 n->devicePixelRatio = dpr;
1663 m_widthMultiplier = 1.0f;
1664 m_heightMultiplier = 1.0f;
1666 QSize itemPixelSize = QSize(width(), height()) * dpr;
1668 m_widthMultiplier = desiredFboSize.width() /
float(itemPixelSize.width());
1669 m_heightMultiplier = desiredFboSize.height() /
float(itemPixelSize.height());
1670 n->devicePixelRatio = 1.0;
1672 desiredFboSize.setWidth(qMax(minFboSize.width(), desiredFboSize.width()));
1673 desiredFboSize.setHeight(qMax(minFboSize.height(), desiredFboSize.height()));
1675 if (desiredFboSize != m_effectiveTextureSize) {
1676 m_effectiveTextureSize = desiredFboSize;
1677 emit effectiveTextureSizeChanged();
1680 n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1681 n->setRect(0, 0, width(), height());
1682 if (checkIsVisible() && isComponentComplete()) {
1683 n->renderer->synchronize(
this, desiredFboSize, n->devicePixelRatio);
1684 if (n->renderer->m_textureNeedsFlip)
1685 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
1686 updateDynamicTextures();
1687 n->scheduleRender();
1693QSGNode *QQuick3DViewport::setupInlineRenderer(QSGNode *node)
1695 QQuick3DSGRenderNode *n =
static_cast<QQuick3DSGRenderNode *>(node);
1698 m_renderNode =
new QQuick3DSGRenderNode;
1703 n->window = window();
1704 n->renderer = createRenderer();
1709 if (!m_effectiveTextureSize.isEmpty()) {
1710 m_effectiveTextureSize = QSize();
1711 emit effectiveTextureSizeChanged();
1714 const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
1719 if (checkIsVisible() && isComponentComplete()) {
1720 n->renderer->synchronize(
this, targetSize, window()->effectiveDevicePixelRatio());
1721 updateDynamicTextures();
1722 n->markDirty(QSGNode::DirtyMaterial);
1729void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
1731 auto renderMode = (mode == Underlay) ? QQuick3DSGDirectRenderer::Underlay
1732 : QQuick3DSGDirectRenderer::Overlay;
1733 if (!m_directRenderer) {
1734 QQuick3DSceneRenderer *sceneRenderer = createRenderer();
1737 m_directRenderer =
new QQuick3DSGDirectRenderer(sceneRenderer, window(), renderMode);
1738 connect(window(), &QQuickWindow::sceneGraphInvalidated,
this, &QQuick3DViewport::cleanupDirectRenderer, Qt::DirectConnection);
1741 if (!m_effectiveTextureSize.isEmpty()) {
1742 m_effectiveTextureSize = QSize();
1743 emit effectiveTextureSizeChanged();
1746 const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
1747 m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
1748 m_directRenderer->setVisibility(isVisible());
1750 m_directRenderer->preSynchronize();
1751 m_directRenderer->renderer()->synchronize(
this, targetSize.toSize(), window()->effectiveDevicePixelRatio());
1752 updateDynamicTextures();
1753 m_directRenderer->requestRender();
1759bool QQuick3DViewport::checkIsVisible()
const
1761 auto childPrivate = QQuickItemPrivate::get(
this);
1762 return (childPrivate->explicitVisible ||
1763 (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
1768
1769
1770
1771
1772
1773
1774
1775
1776void QQuick3DViewport::processPickedObject(
const QSSGRenderPickResult &pickResult,
1778 QPointerEvent *event,
1779 QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1781 QQuickItem *subsceneRootItem =
nullptr;
1782 QPointF subscenePosition;
1783 const auto backendObject = pickResult.m_hitObject;
1784 const auto frontendObject = findFrontendNode(backendObject);
1785 if (!frontendObject)
1791 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1792 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1795 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1797 subsceneRootItem = item2D->contentItem();
1798 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1802 subscenePosition = pickResult.m_localUVCoords.toPointF();
1806 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1808 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1810 int materialSubset = pickResult.m_subset;
1811 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1813 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1814 materialSubset = backendModel->materials.size() - 1;
1815 if (materialSubset < 0)
1817 const auto backendMaterial = backendModel->materials.at(materialSubset);
1818 const auto frontendMaterial =
static_cast<QQuick3DMaterial*>(findFrontendNode(backendMaterial));
1819 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1821 if (subsceneRootItem) {
1823 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1824 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1829 if (subsceneRootItem) {
1830 SubsceneInfo &subscene = visitedSubscenes[subsceneRootItem];
1831 subscene.obj = frontendObject;
1832 if (subscene.eventPointScenePositions.size() != event->pointCount()) {
1834 constexpr QPointF inf(-qt_inf(), -qt_inf());
1835 subscene.eventPointScenePositions.resize(event->pointCount(), inf);
1837 subscene.eventPointScenePositions[pointIndex] = subscenePosition;
1842
1843
1844
1845
1846
1847
1848
1849
1851QQuickItem *QQuick3DViewport::getSubSceneRootItem(QQuick3DMaterial *material)
const
1856 QQuickItem *subsceneRootItem =
nullptr;
1857 const auto frontendMaterialPrivate = QQuick3DObjectPrivate::get(material);
1859 if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::DefaultMaterial) {
1861 const auto defaultMaterial = qobject_cast<QQuick3DDefaultMaterial *>(material);
1862 if (defaultMaterial) {
1864 if (defaultMaterial->diffuseMap() && defaultMaterial->diffuseMap()->sourceItem())
1865 subsceneRootItem = defaultMaterial->diffuseMap()->sourceItem();
1868 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::PrincipledMaterial) {
1870 const auto principledMaterial = qobject_cast<QQuick3DPrincipledMaterial *>(material);
1871 if (principledMaterial) {
1873 if (principledMaterial->baseColorMap() && principledMaterial->baseColorMap()->sourceItem())
1874 subsceneRootItem = principledMaterial->baseColorMap()->sourceItem();
1876 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::SpecularGlossyMaterial) {
1878 const auto specularGlossyMaterial = qobject_cast<QQuick3DSpecularGlossyMaterial *>(material);
1879 if (specularGlossyMaterial) {
1881 if (specularGlossyMaterial->albedoMap() && specularGlossyMaterial->albedoMap()->sourceItem())
1882 subsceneRootItem = specularGlossyMaterial->albedoMap()->sourceItem();
1884 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
1886 const auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material);
1887 if (customMaterial) {
1889 const auto &texturesInputs = customMaterial->m_dynamicTextureMaps;
1890 for (
const auto &textureInput : texturesInputs) {
1891 if (
auto texture = textureInput->texture()) {
1892 if (texture->sourceItem()) {
1893 subsceneRootItem = texture->sourceItem();
1900 return subsceneRootItem;
1905
1906
1907QQuick3DPickResult QQuick3DViewport::getNearestPickResult(
const QVarLengthArray<QSSGRenderPickResult, 20> &pickResults)
const
1909 for (
const auto &result : pickResults) {
1910 auto pickResult = processPickResult(result);
1911 if (pickResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1915 return QQuick3DPickResult();
1919
1920
1921
1922
1923
1924bool QQuick3DViewport::forwardEventToSubscenes(QPointerEvent *event,
1926 QQuick3DSceneRenderer *renderer,
1927 const QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1934 QVarLengthArray<QPointF, 16> originalScenePositions;
1935 originalScenePositions.resize(event->pointCount());
1936 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1937 originalScenePositions[pointIndex] = event->point(pointIndex).scenePosition();
1938 for (
const auto &subscene : visitedSubscenes) {
1939 QQuickItem *subsceneRoot = subscene.first;
1940 const auto &subsceneInfo = subscene.second;
1941 Q_ASSERT(subsceneInfo.eventPointScenePositions.size() == event->pointCount());
1942 auto da = QQuickItemPrivate::get(subsceneRoot)->deliveryAgent();
1943 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1944 const auto &pt = subsceneInfo.eventPointScenePositions.at(pointIndex);
1949 QEventPoint &ep = event->point(pointIndex);
1950 QMutableEventPoint::setPosition(ep, pt);
1951 QMutableEventPoint::setScenePosition(ep, pt);
1954 if (event->isBeginEvent())
1955 da->setSceneTransform(
nullptr);
1956 if (da->event(event)) {
1958 if (QQuickDeliveryAgentPrivate::anyPointGrabbed(event) && !useRayPicking) {
1963 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(subsceneInfo.obj);
1964 const bool item2Dcase = (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D);
1965 ViewportTransformHelper *transform =
new ViewportTransformHelper;
1966 transform->viewport =
const_cast<QQuick3DViewport *>(
this);
1967 transform->renderer = renderer;
1968 transform->sceneParentNode =
static_cast<QSSGRenderNode*>(frontendObjectPrivate->spatialNode);
1969 transform->targetItem = subsceneRoot;
1970 transform->scaleX = window()->effectiveDevicePixelRatio() * m_widthMultiplier;
1971 transform->scaleY = window()->effectiveDevicePixelRatio() * m_heightMultiplier;
1972 transform->uvCoordsArePixels = item2Dcase;
1973 transform->setOnDeliveryAgent(da);
1974 qCDebug(lcPick) << event->type() <<
"created ViewportTransformHelper on" << da;
1976 }
else if (event->type() != QEvent::HoverMove) {
1977 qCDebug(lcPick) << subsceneRoot <<
"didn't want" << event;
1979 event->setAccepted(
false);
1981 if (visitedSubscenes.isEmpty()) {
1982 event->setAccepted(
false);
1984 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1985 QMutableEventPoint::setScenePosition(event->point(pointIndex), originalScenePositions.at(pointIndex));
1991 if (event->isEndEvent() && useRayPicking) {
1992 if (event->isSinglePointEvent()) {
1993 if (
static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
1994 auto &firstPt = event->point(0);
1995 event->setExclusiveGrabber(firstPt,
nullptr);
1996 event->clearPassiveGrabbers(firstPt);
1999 for (
auto &point : event->points()) {
2000 if (point.state() == QEventPoint::State::Released) {
2001 event->setExclusiveGrabber(point,
nullptr);
2002 event->clearPassiveGrabbers(point);
2012bool QQuick3DViewport::internalPick(QPointerEvent *event,
const QVector3D &origin,
const QVector3D &direction)
const
2014 QQuick3DSceneRenderer *renderer = getRenderer();
2015 if (!renderer || !event)
2018 QFlatMap<QQuickItem*, SubsceneInfo> visitedSubscenes;
2019 const bool useRayPicking = !direction.isNull();
2021 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
2022 auto &eventPoint = event->point(pointIndex);
2023 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2024 if (Q_UNLIKELY(useRayPicking))
2025 pickResults = getPickResults(renderer, origin, direction);
2027 pickResults = getPickResults(renderer, eventPoint);
2029 if (!pickResults.isEmpty())
2030 for (
const auto &pickResult : pickResults)
2031 processPickedObject(pickResult, pointIndex, event, visitedSubscenes);
2033 eventPoint.setAccepted(
false);
2036 return forwardEventToSubscenes(event, useRayPicking, renderer, visitedSubscenes);
2039bool QQuick3DViewport::singlePointPick(QSinglePointEvent *event,
const QVector3D &origin,
const QVector3D &direction)
2041 QQuick3DSceneRenderer *renderer = getRenderer();
2042 if (!renderer || !event)
2045 QSSGRenderRay ray(origin, direction);
2047 Q_ASSERT(event->pointCount() == 1);
2048 QPointF originalPosition = event->point(0).scenePosition();
2050 auto pickResults = renderer->syncPickAll(ray);
2052 bool delivered =
false;
2054 constexpr float jitterLimit = 2.5;
2055 bool withinJitterLimit =
false;
2057 for (
const auto &pickResult : pickResults) {
2058 auto [item, position] = getItemAndPosition(pickResult);
2061 if (item == m_prevMouseItem && (position - m_prevMousePos).manhattanLength() < jitterLimit && !event->button()) {
2062 withinJitterLimit =
true;
2065 auto da = QQuickItemPrivate::get(item)->deliveryAgent();
2066 QEventPoint &ep = event->point(0);
2067 QMutableEventPoint::setPosition(ep, position);
2068 QMutableEventPoint::setScenePosition(ep, position);
2069 if (da->event(event)) {
2071 if (event->type() == QEvent::MouseButtonPress) {
2072 m_prevMouseItem = item;
2073 m_prevMousePos = position;
2074 withinJitterLimit =
true;
2080 QMutableEventPoint::setScenePosition(event->point(0), originalPosition);
2081 if (!withinJitterLimit)
2082 m_prevMouseItem =
nullptr;
2087 if (event->isEndEvent()) {
2088 if (event->buttons() == Qt::NoButton) {
2089 auto &firstPt = event->point(0);
2090 event->setExclusiveGrabber(firstPt,
nullptr);
2091 event->clearPassiveGrabbers(firstPt);
2098QPair<QQuickItem *, QPointF> QQuick3DViewport::getItemAndPosition(
const QSSGRenderPickResult &pickResult)
const
2100 QQuickItem *subsceneRootItem =
nullptr;
2101 QPointF subscenePosition;
2102 const auto backendObject = pickResult.m_hitObject;
2103 const auto frontendObject = findFrontendNode(backendObject);
2104 if (!frontendObject)
2106 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
2107 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
2110 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
2112 subsceneRootItem = item2D->contentItem();
2113 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
2117 subscenePosition = pickResult.m_localUVCoords.toPointF();
2121 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
2123 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
2125 int materialSubset = pickResult.m_subset;
2126 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
2128 if (backendModel->materials.size() < (pickResult.m_subset + 1))
2129 materialSubset = backendModel->materials.size() - 1;
2130 if (materialSubset < 0)
2132 const auto backendMaterial = backendModel->materials.at(materialSubset);
2133 const auto frontendMaterial =
static_cast<QQuick3DMaterial *>(findFrontendNode(backendMaterial));
2134 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
2136 if (subsceneRootItem) {
2138 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
2139 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
2142 return {subsceneRootItem, subscenePosition};
2145QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
2146 const QVector3D &origin,
2147 const QVector3D &direction)
const
2149 const QSSGRenderRay ray(origin, direction);
2150 return renderer->syncPickAll(ray);
2153QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
const QEventPoint &eventPoint)
const
2155 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2156 QPointF realPosition = eventPoint.position() * window()->effectiveDevicePixelRatio();
2158 realPosition.rx() *= m_widthMultiplier;
2159 realPosition.ry() *= m_heightMultiplier;
2160 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(realPosition);
2161 if (rayResult.has_value())
2162 pickResults = renderer->syncPickAll(rayResult.value());
2167
2168
2169
2170
2171
2172QQuick3DObject *QQuick3DViewport::findFrontendNode(
const QSSGRenderGraphObject *backendObject)
const
2177 const auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2178 QQuick3DObject *frontendObject = sceneManager->lookUpNode(backendObject);
2179 if (!frontendObject && m_importScene) {
2180 const auto importSceneManager = QQuick3DObjectPrivate::get(m_importScene)->sceneManager;
2181 frontendObject = importSceneManager->lookUpNode(backendObject);
2183 return frontendObject;
2186QQuick3DPickResult QQuick3DViewport::processPickResult(
const QSSGRenderPickResult &pickResult)
const
2188 if (!pickResult.m_hitObject)
2189 return QQuick3DPickResult();
2191 QQuick3DObject *frontendObject = findFrontendNode(pickResult.m_hitObject);
2193 QQuick3DModel *model = qobject_cast<QQuick3DModel *>(frontendObject);
2195 auto itemAndPosition = getItemAndPosition(pickResult);
2196 return QQuick3DPickResult(model,
2197 ::sqrtf(pickResult.m_distanceSq),
2198 pickResult.m_localUVCoords,
2199 pickResult.m_scenePosition,
2200 pickResult.m_localPosition,
2201 pickResult.m_faceNormal,
2202 pickResult.m_sceneNormal,
2203 pickResult.m_instanceIndex,
2204 itemAndPosition.first);
2207 QQuick3DItem2D *frontend2DItem = qobject_cast<QQuick3DItem2D *>(frontendObject);
2208 if (frontend2DItem && frontend2DItem->contentItem()) {
2210 const QPointF subscenePosition = pickResult.m_localUVCoords.toPointF();
2211 const auto child = frontend2DItem->contentItem()->childAt(subscenePosition.x(), subscenePosition.y());
2213 return QQuick3DPickResult(child,
2214 ::sqrtf(pickResult.m_distanceSq),
2215 QVector2D(frontend2DItem->contentItem()->mapToItem(child, subscenePosition)),
2216 pickResult.m_scenePosition,
2217 pickResult.m_localPosition,
2218 pickResult.m_faceNormal);
2222 return QQuick3DPickResult();
2227QQuick3DSceneManager *QQuick3DViewport::findChildSceneManager(QQuick3DObject *inObject, QQuick3DSceneManager *manager)
2232 auto children = QQuick3DObjectPrivate::get(inObject)->childItems;
2233 for (
auto *child : std::as_const(children)) {
2234 if (
auto m = QQuick3DObjectPrivate::get(child)->sceneManager) {
2238 manager = findChildSceneManager(child, manager);
2243void QQuick3DViewport::updateInputProcessing()
2246 setAcceptTouchEvents(m_enableInputProcessing);
2247 setAcceptHoverEvents(m_enableInputProcessing);
2248 setAcceptedMouseButtons(m_enableInputProcessing ? Qt::AllButtons : Qt::NoButton);
2251void QQuick3DViewport::onReleaseCachedResources()
2253 if (
auto renderer = getRenderer())
2254 renderer->releaseCachedResources();
2258
2259
2260
2261
2262
2263
2264QQmlListProperty<QQuick3DObject> QQuick3DViewport::extensions()
2266 return QQmlListProperty<QQuick3DObject>{
this,
2267 &m_extensionListDirty,
2268 &QQuick3DExtensionListHelper::extensionAppend,
2269 &QQuick3DExtensionListHelper::extensionCount,
2270 &QQuick3DExtensionListHelper::extensionAt,
2271 &QQuick3DExtensionListHelper::extensionClear,
2272 &QQuick3DExtensionListHelper::extensionReplace,
2273 &QQuick3DExtensionListHelper::extensionRemoveLast};
2277
2278
2279void QQuick3DViewport::rebuildExtensionList()
2281 m_extensionListDirty =
true;
2286
2287
2288
2289
2290
2291QQuick3DViewport::QQuick3DViewport(PrivateInstanceType type, QQuickItem *parent)
2292 : QQuick3DViewport(parent)
2294 m_isXrViewInstance = type == PrivateInstanceType::XrViewInstance;
2297void QQuick3DViewport::updateCameraForLayer(
const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode)
2299 layerNode.explicitCameras.clear();
2300 if (!view3D.m_multiViewCameras.isEmpty()) {
2301 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
2302 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
2303 }
else if (view3D.camera()) {
2304 if (QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode))
2305 layerNode.explicitCameras.append(camera);
2310 for (QSSGRenderCamera *camera : std::as_const(layerNode.explicitCameras)) {
2311 if (!camera->parent)
2312 layerNode.addChild(*camera);
2316void QQuick3DViewport::updateSceneManagerForImportScene()
2318 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2319 if (!privateObject->sceneManager) {
2321 QQuick3DSceneManager *manager = findChildSceneManager(m_importScene);
2324 manager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2326 manager->setWindow(window());
2327 privateObject->refSceneManager(*manager);
2332 if (!privateObject->sceneManager)
2336 connect(privateObject->sceneManager, &QQuick3DSceneManager::needsUpdate,
2337 this, &QQuickItem::update, Qt::UniqueConnection);
2338 connect(privateObject->sceneManager, &QObject::destroyed,
2339 this, [&](QObject *) {
2340 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2341 privateObject->sceneManager =
nullptr;
2342 updateSceneManagerForImportScene();
2343 }, Qt::DirectConnection);
2345 QQuick3DNode *scene = m_importScene;
2347 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
2348 scene = rn ? rn->view3D()->importScene() :
nullptr;
2351 connect(QQuick3DObjectPrivate::get(scene)->sceneManager,
2352 &QQuick3DSceneManager::needsUpdate,
2353 this, &QQuickItem::update, Qt::UniqueConnection);
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2373QQuick3DViewport::RenderOverrides QQuick3DViewport::renderOverrides()
const
2375 return m_renderOverrides;
2378void QQuick3DViewport::setRenderOverrides(RenderOverrides newRenderOverrides)
2380 if (m_renderOverrides == newRenderOverrides)
2382 m_renderOverrides = newRenderOverrides;
2383 emit renderOverridesChanged();
void run() override
Implement this pure virtual function in your subclass.
CleanupJob(QQuick3DSGDirectRenderer *renderer)
static void extensionClear(QQmlListProperty< QQuick3DObject > *list)
static void extensionReplace(QQmlListProperty< QQuick3DObject > *list, qsizetype idx, QQuick3DObject *o)
static void extensionAppend(QQmlListProperty< QQuick3DObject > *list, QQuick3DObject *extension)
static QQuick3DObject * extensionAt(QQmlListProperty< QQuick3DObject > *list, qsizetype index)
static void extensionRemoveLast(QQmlListProperty< QQuick3DObject > *list)
static qsizetype extensionCount(QQmlListProperty< QQuick3DObject > *list)
Combined button and popup list for selecting options.
static qsizetype ssgn_count(QQmlListProperty< QObject > *property)
static QObject * ssgn_at(QQmlListProperty< QObject > *property, qsizetype i)
static void ssgn_append(QQmlListProperty< QObject > *property, QObject *obj)
static void ssgn_clear(QQmlListProperty< QObject > *property)