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
1018QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y)
const
1020 QQuick3DSceneRenderer *renderer = getRenderer();
1022 return QQuick3DPickResult();
1024 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1025 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1026 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1027 if (!rayResult.has_value())
1028 return QQuick3DPickResult();
1030 const auto resultList = renderer->syncPick(rayResult.value());
1031 return getNearestPickResult(resultList);
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y, QQuick3DModel *model)
const
1048 QQuick3DSceneRenderer *renderer = getRenderer();
1050 return QQuick3DPickResult();
1052 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1053 qreal(y) * window()->effectiveDevicePixelRatio());
1054 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1056 if (!rayResult.has_value())
1057 return QQuick3DPickResult();
1059 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1060 const auto resultList = renderer->syncPickOne(rayResult.value(), renderNode);
1061 return getNearestPickResult(resultList);
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081QList<QQuick3DPickResult> QQuick3DViewport::pickSubset(
float x,
float y,
const QJSValue &models)
const
1083 QQuick3DSceneRenderer *renderer = getRenderer();
1087 QVarLengthArray<QSSGRenderNode*> renderNodes;
1089 if (models.isArray()) {
1090 const auto length = models.property(QStringLiteral(
"length")).toInt();
1094 for (
int i = 0; i < length; ++i) {
1095 const auto isQObject = models.property(i).isQObject();
1097 qmlWarning(
this) <<
"Type provided for picking is not a QObject. Needs to be of type QQuick3DModel.";
1100 const auto obj = models.property(i).toQObject();
1101 const auto model = qobject_cast<QQuick3DModel *>(obj);
1103 qmlWarning(
this) <<
"Type " << obj->metaObject()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1106 const auto priv = QQuick3DObjectPrivate::get(model);
1107 if (priv && priv->spatialNode) {
1108 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1113 const auto subsetVariant = models.toVariant();
1114 if (!subsetVariant.isValid() || !subsetVariant.canConvert<QQmlListReference>())
1117 const auto list = subsetVariant.value<QQmlListReference>();
1120 if (list.listElementType()->className() != QQuick3DModel::staticMetaObject.className()) {
1121 qmlWarning(
this) <<
"Type " << list.listElementType()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1124 for (
int i = 0; i < list.count(); ++i) {
1125 auto model =
static_cast<QQuick3DModel *>(list.at(i));
1128 auto priv = QQuick3DObjectPrivate::get(model);
1129 if (priv && priv->spatialNode) {
1130 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1135 if (renderNodes.empty())
1138 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1139 qreal(y) * window()->effectiveDevicePixelRatio());
1140 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1141 if (!rayResult.has_value())
1144 const auto resultList = renderer->syncPickSubset(rayResult.value(), renderNodes);
1146 QList<QQuick3DPickResult> processedResultList;
1147 processedResultList.reserve(resultList.size());
1148 for (
const auto &result : resultList)
1149 processedResultList.append(processPickResult(result));
1151 return processedResultList;
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168QList<QQuick3DPickResult> QQuick3DViewport::pickAll(
float x,
float y)
const
1170 QQuick3DSceneRenderer *renderer = getRenderer();
1172 return QList<QQuick3DPickResult>();
1174 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1175 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1176 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1177 if (!rayResult.has_value())
1178 return QList<QQuick3DPickResult>();
1180 const auto resultList = renderer->syncPickAll(rayResult.value());
1181 QList<QQuick3DPickResult> processedResultList;
1182 processedResultList.reserve(resultList.size());
1183 for (
const auto &result : resultList)
1184 processedResultList.append(processPickResult(result));
1186 return processedResultList;
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction)
const
1204 QQuick3DSceneRenderer *renderer = getRenderer();
1206 return QQuick3DPickResult();
1208 const QSSGRenderRay ray(origin, direction);
1209 const auto resultList = renderer->syncPick(ray);
1210 return getNearestPickResult(resultList);
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229QList<QQuick3DPickResult> QQuick3DViewport::rayPickAll(
const QVector3D &origin,
const QVector3D &direction)
const
1231 QQuick3DSceneRenderer *renderer = getRenderer();
1233 return QList<QQuick3DPickResult>();
1235 const QSSGRenderRay ray(origin, direction);
1237 const auto resultList = renderer->syncPickAll(ray);
1238 QList<QQuick3DPickResult> processedResultList;
1239 processedResultList.reserve(resultList.size());
1240 for (
const auto &result : resultList) {
1241 auto processedResult = processPickResult(result);
1242 if (processedResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1243 processedResultList.append(processedResult);
1246 return processedResultList;
1250
1251
1252
1253
1254
1255
1256
1257QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction, QQuick3DModel *model)
const
1259 QQuick3DSceneRenderer *renderer = getRenderer();
1261 return QQuick3DPickResult();
1263 const QSSGRenderRay ray(origin, direction);
1265 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1266 const auto resultList = renderer->syncPickOne(ray, renderNode);
1267 return getNearestPickResult(resultList);
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280QQuick3DPickResult QQuick3DViewport::closestPointPick(
const QVector3D &origin,
float radius, QQuick3DModel *model)
const
1282 QQuick3DSceneRenderer *renderer = getRenderer();
1285 return QQuick3DPickResult();
1286 QSSGRenderNode *renderNode =
nullptr;
1288 renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1289 if (Q_UNLIKELY(!renderNode))
1290 return QQuick3DPickResult{};
1293 const auto pickResult = renderer->syncPickClosestPoint(origin, radius * radius, renderNode);
1294 if (!pickResult.has_value())
1295 return QQuick3DPickResult{};
1296 return processPickResult(pickResult.value());
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312QList<QQuick3DObject *> QQuick3DViewport::pickInRect(
const QPointF &start,
const QPointF &end)
const
1314 const qreal minX = qMin(start.x(), end.x());
1315 const qreal maxX = qMax(start.x(), end.x());
1316 const qreal minY = qMin(start.y(), end.y());
1317 const qreal maxY = qMax(start.y(), end.y());
1319 const qreal ndc[4] = {
1320 2.0f * minX / width() - 1.0f,
1321 2.0f * maxX / width() - 1.0f,
1323 1.0f - 2.0f * maxY / height(),
1324 1.0f - 2.0f * minY / height(),
1327 const float near = 0.0f;
1328 const float far = 1.0f;
1329 enum { L, R, B, T };
1330 const QVector4D ndcCorners[8] = {
1332 QVector4D(ndc[L], ndc[B], near, 1.0f),
1333 QVector4D(ndc[R], ndc[B], near, 1.0f),
1334 QVector4D(ndc[L], ndc[T], near, 1.0f),
1335 QVector4D(ndc[R], ndc[T], near, 1.0f),
1337 QVector4D(ndc[L], ndc[B], far, 1.0f),
1338 QVector4D(ndc[R], ndc[B], far, 1.0f),
1339 QVector4D(ndc[L], ndc[T], far, 1.0f),
1340 QVector4D(ndc[R], ndc[T], far, 1.0f),
1343 QMatrix4x4 viewProjection;
1344 if (
this->camera()) {
1345 if (
auto camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(
this->camera())->spatialNode))
1346 camera->calculateViewProjectionMatrix(camera->localTransform, camera->projection, viewProjection);
1348 QMatrix4x4 viewProjectionInverted = viewProjection.inverted();
1350 QVector3D worldCorners[8];
1351 for (
int i = 0; i < 8; ++i) {
1352 QVector4D worldPoint = viewProjectionInverted * ndcCorners[i];
1353 worldCorners[i] = worldPoint.toVector3D() / worldPoint.w();
1372 const QSSGFrustum frustum {
1373 QSSGPlane(worldCorners[0], worldCorners[4], worldCorners[6]),
1374 QSSGPlane(worldCorners[1], worldCorners[3], worldCorners[7]),
1375 QSSGPlane(worldCorners[0], worldCorners[1], worldCorners[5]),
1376 QSSGPlane(worldCorners[2], worldCorners[6], worldCorners[7]),
1377 QSSGPlane(worldCorners[0], worldCorners[2], worldCorners[3]),
1378 QSSGPlane(worldCorners[5], worldCorners[7], worldCorners[6]),
1381 QList<QQuick3DObject *> ret;
1382 if (QQuick3DSceneRenderer *renderer = getRenderer()) {
1383 auto nodes = renderer->syncPickInFrustum(frustum);
1384 for (
const auto *node : std::as_const(nodes)) {
1385 if (QQuick3DObject *m = findFrontendNode(node))
1393void QQuick3DViewport::processPointerEventFromRay(
const QVector3D &origin,
const QVector3D &direction, QPointerEvent *event)
const
1395 internalPick(event, origin, direction);
1402class SyntheticTouchDevice :
public QPointingDevice
1405 SyntheticTouchDevice(QObject *parent =
nullptr)
1406 : QPointingDevice(QLatin1StringView(
"QtQuick3D Touch Synthesizer"),
1408 DeviceType::TouchScreen,
1409 PointerType::Finger,
1410 Capability::Position,
1412 QString(), QPointingDeviceUniqueId(),
1420
1421
1422
1423
1424
1425
1426
1427
1428
1430void QQuick3DViewport::setTouchpoint(QQuickItem *target,
const QPointF &position,
int pointId,
bool pressed)
1432 if (pointId >= m_touchState.size())
1433 m_touchState.resize(pointId + 1);
1434 auto prevState = m_touchState[pointId];
1436 const bool sameTarget = prevState.target == target;
1437 const bool wasPressed = prevState.isPressed;
1439 const bool isPress = pressed && (!sameTarget || !wasPressed);
1440 const bool isRelease = !pressed && wasPressed && sameTarget;
1445 if (!sameTarget && wasPressed)
1446 qWarning(
"QQuick3DViewport::setTouchpoint missing release event");
1448 if (!pressed && !wasPressed) {
1453 m_touchState[pointId] = { target, position, pressed };
1455 if (!m_syntheticTouchDevice)
1456 m_syntheticTouchDevice =
new SyntheticTouchDevice(
this);
1458 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(m_syntheticTouchDevice);
1460 auto makePoint = [devPriv](
int id, QEventPoint::State pointState, QPointF pos, quint64 timestamp) -> QEventPoint {
1461 auto epd = devPriv->pointById(id);
1462 auto &ep = epd->eventPoint;
1463 if (pointState != QEventPoint::State::Stationary)
1464 ep.setAccepted(
false);
1466 auto res = QMutableEventPoint::withTimeStamp(timestamp, id, pointState, pos, pos, pos);
1467 QMutableEventPoint::update(res, ep);
1469 if (pointState == QEventPoint::State::Pressed)
1470 QMutableEventPoint::setGlobalPressPosition(res, pos);
1471 else if (ep.state() != QEventPoint::State::Unknown)
1472 QMutableEventPoint::setGlobalPressPosition(res, ep.globalPressPosition());
1477 auto sendTouchEvent = [&](QQuickItem *t,
const QPointF &position,
int pointId, QEventPoint::State pointState, quint64 timestamp) ->
void {
1478 QList<QEventPoint> points;
1479 bool otherPoint =
false;
1480 for (
int i = 0; i < m_touchState.size(); ++i) {
1481 const auto &ts = m_touchState[i];
1485 auto newPoint = makePoint(i, pointState, position, timestamp);
1487 }
else if (ts.isPressed) {
1489 points << makePoint(i, QEventPoint::Stationary, ts.position, timestamp);
1494 if (pointState == QEventPoint::Pressed && !otherPoint)
1495 type = QEvent::Type::TouchBegin;
1496 else if (pointState == QEventPoint::Released && !otherPoint)
1497 type = QEvent::Type::TouchEnd;
1499 type = QEvent::Type::TouchUpdate;
1501 QTouchEvent ev(type, m_syntheticTouchDevice, {}, points);
1502 ev.setTimestamp(timestamp);
1506 auto da = QQuickItemPrivate::get(t)->deliveryAgent();
1507 bool handled = da->event(&ev);
1512 if (ev.isEndEvent()) {
1513 for (
auto &point : ev.points()) {
1514 if (point.state() == QEventPoint::State::Released) {
1515 ev.setExclusiveGrabber(point,
nullptr);
1516 ev.clearPassiveGrabbers(point);
1522 auto timestamp = QDateTime::currentMSecsSinceEpoch();
1525 if (prevState.target && !sameTarget)
1526 sendTouchEvent(prevState.target, prevState.position, pointId, QEventPoint::Released, timestamp);
1529 QEventPoint::State newState = isPress ? QEventPoint::Pressed : isRelease ? QEventPoint::Released : QEventPoint::Updated;
1530 sendTouchEvent(target, position, pointId, newState, timestamp);
1533QQuick3DLightmapBaker *QQuick3DViewport::maybeLightmapBaker()
1535 return m_lightmapBaker;
1538QQuick3DLightmapBaker *QQuick3DViewport::lightmapBaker()
1540 if (!m_lightmapBaker)
1541 m_lightmapBaker=
new QQuick3DLightmapBaker(
this);
1543 return m_lightmapBaker;
1547
1548
1549void QQuick3DViewport::bakeLightmap()
1551 QQuick3DSceneRenderer *renderer = getRenderer();
1552 if (!renderer || !renderer->m_layer->renderData)
1555 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1557 if (!currentlyBaking)
1558 lightmapBaker()->bake();
1562
1563
1564void QQuick3DViewport::denoiseLightmap()
1566 QQuick3DSceneRenderer *renderer = getRenderer();
1567 if (!renderer || !renderer->m_layer->renderData)
1570 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1572 if (!currentlyBaking)
1573 lightmapBaker()->denoise();
1577void QQuick3DViewport::setGlobalPickingEnabled(
bool isEnabled)
1579 QQuick3DSceneRenderer *renderer = getRenderer();
1583 renderer->setGlobalPickingEnabled(isEnabled);
1586void QQuick3DViewport::invalidateSceneGraph()
1589 m_renderNode =
nullptr;
1592QQuick3DSceneRenderer *QQuick3DViewport::getRenderer()
const
1594 QQuick3DSceneRenderer *renderer =
nullptr;
1596 renderer = m_node->renderer;
1597 }
else if (m_renderNode) {
1598 renderer = m_renderNode->renderer;
1599 }
else if (m_directRenderer) {
1600 renderer = m_directRenderer->renderer();
1605void QQuick3DViewport::updateDynamicTextures()
1610 const auto &sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
1611 for (
auto *texture : std::as_const(sceneManager->qsgDynamicTextures))
1612 texture->updateTexture();
1614 QQuick3DNode *scene = m_importScene;
1616 const auto &importSm = QQuick3DObjectPrivate::get(scene)->sceneManager;
1617 if (importSm != sceneManager) {
1618 for (
auto *texture : std::as_const(importSm->qsgDynamicTextures))
1619 texture->updateTexture();
1623 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
1624 scene = rn ? rn->view3D()->importScene() :
nullptr;
1628QSGNode *QQuick3DViewport::setupOffscreenRenderer(QSGNode *node)
1630 SGFramebufferObjectNode *n =
static_cast<SGFramebufferObjectNode *>(node);
1634 m_node =
new SGFramebufferObjectNode;
1639 n->window = window();
1640 n->renderer = createRenderer();
1643 n->renderer->fboNode = n;
1645 connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
1648 const qreal dpr = window()->effectiveDevicePixelRatio();
1649 const QSize minFboSize = QQuickItemPrivate::get(
this)->sceneGraphContext()->minimumFBOSize();
1650 QSize desiredFboSize = QSize(m_explicitTextureWidth, m_explicitTextureHeight);
1651 if (desiredFboSize.isEmpty()) {
1652 desiredFboSize = QSize(width(), height()) * dpr;
1653 n->devicePixelRatio = dpr;
1655 m_widthMultiplier = 1.0f;
1656 m_heightMultiplier = 1.0f;
1658 QSize itemPixelSize = QSize(width(), height()) * dpr;
1660 m_widthMultiplier = desiredFboSize.width() /
float(itemPixelSize.width());
1661 m_heightMultiplier = desiredFboSize.height() /
float(itemPixelSize.height());
1662 n->devicePixelRatio = 1.0;
1664 desiredFboSize.setWidth(qMax(minFboSize.width(), desiredFboSize.width()));
1665 desiredFboSize.setHeight(qMax(minFboSize.height(), desiredFboSize.height()));
1667 if (desiredFboSize != m_effectiveTextureSize) {
1668 m_effectiveTextureSize = desiredFboSize;
1669 emit effectiveTextureSizeChanged();
1672 n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1673 n->setRect(0, 0, width(), height());
1674 if (checkIsVisible() && isComponentComplete()) {
1675 n->renderer->synchronize(
this, desiredFboSize, n->devicePixelRatio);
1676 if (n->renderer->m_textureNeedsFlip)
1677 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
1678 updateDynamicTextures();
1679 n->scheduleRender();
1685QSGNode *QQuick3DViewport::setupInlineRenderer(QSGNode *node)
1687 QQuick3DSGRenderNode *n =
static_cast<QQuick3DSGRenderNode *>(node);
1690 m_renderNode =
new QQuick3DSGRenderNode;
1695 n->window = window();
1696 n->renderer = createRenderer();
1701 if (!m_effectiveTextureSize.isEmpty()) {
1702 m_effectiveTextureSize = QSize();
1703 emit effectiveTextureSizeChanged();
1706 const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
1711 if (checkIsVisible() && isComponentComplete()) {
1712 n->renderer->synchronize(
this, targetSize, window()->effectiveDevicePixelRatio());
1713 updateDynamicTextures();
1714 n->markDirty(QSGNode::DirtyMaterial);
1721void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
1723 auto renderMode = (mode == Underlay) ? QQuick3DSGDirectRenderer::Underlay
1724 : QQuick3DSGDirectRenderer::Overlay;
1725 if (!m_directRenderer) {
1726 QQuick3DSceneRenderer *sceneRenderer = createRenderer();
1729 m_directRenderer =
new QQuick3DSGDirectRenderer(sceneRenderer, window(), renderMode);
1730 connect(window(), &QQuickWindow::sceneGraphInvalidated,
this, &QQuick3DViewport::cleanupDirectRenderer, Qt::DirectConnection);
1733 if (!m_effectiveTextureSize.isEmpty()) {
1734 m_effectiveTextureSize = QSize();
1735 emit effectiveTextureSizeChanged();
1738 const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
1739 m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
1740 m_directRenderer->setVisibility(isVisible());
1742 m_directRenderer->preSynchronize();
1743 m_directRenderer->renderer()->synchronize(
this, targetSize.toSize(), window()->effectiveDevicePixelRatio());
1744 updateDynamicTextures();
1745 m_directRenderer->requestRender();
1751bool QQuick3DViewport::checkIsVisible()
const
1753 auto childPrivate = QQuickItemPrivate::get(
this);
1754 return (childPrivate->explicitVisible ||
1755 (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
1760
1761
1762
1763
1764
1765
1766
1767
1768void QQuick3DViewport::processPickedObject(
const QSSGRenderPickResult &pickResult,
1770 QPointerEvent *event,
1771 QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1773 QQuickItem *subsceneRootItem =
nullptr;
1774 QPointF subscenePosition;
1775 const auto backendObject = pickResult.m_hitObject;
1776 const auto frontendObject = findFrontendNode(backendObject);
1777 if (!frontendObject)
1783 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1784 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1787 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1789 subsceneRootItem = item2D->contentItem();
1790 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1794 subscenePosition = pickResult.m_localUVCoords.toPointF();
1798 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1800 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1802 int materialSubset = pickResult.m_subset;
1803 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1805 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1806 materialSubset = backendModel->materials.size() - 1;
1807 if (materialSubset < 0)
1809 const auto backendMaterial = backendModel->materials.at(materialSubset);
1810 const auto frontendMaterial =
static_cast<QQuick3DMaterial*>(findFrontendNode(backendMaterial));
1811 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1813 if (subsceneRootItem) {
1815 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1816 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1821 if (subsceneRootItem) {
1822 SubsceneInfo &subscene = visitedSubscenes[subsceneRootItem];
1823 subscene.obj = frontendObject;
1824 if (subscene.eventPointScenePositions.size() != event->pointCount()) {
1826 constexpr QPointF inf(-qt_inf(), -qt_inf());
1827 subscene.eventPointScenePositions.resize(event->pointCount(), inf);
1829 subscene.eventPointScenePositions[pointIndex] = subscenePosition;
1834
1835
1836
1837
1838
1839
1840
1841
1843QQuickItem *QQuick3DViewport::getSubSceneRootItem(QQuick3DMaterial *material)
const
1848 QQuickItem *subsceneRootItem =
nullptr;
1849 const auto frontendMaterialPrivate = QQuick3DObjectPrivate::get(material);
1851 if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::DefaultMaterial) {
1853 const auto defaultMaterial = qobject_cast<QQuick3DDefaultMaterial *>(material);
1854 if (defaultMaterial) {
1856 if (defaultMaterial->diffuseMap() && defaultMaterial->diffuseMap()->sourceItem())
1857 subsceneRootItem = defaultMaterial->diffuseMap()->sourceItem();
1860 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::PrincipledMaterial) {
1862 const auto principledMaterial = qobject_cast<QQuick3DPrincipledMaterial *>(material);
1863 if (principledMaterial) {
1865 if (principledMaterial->baseColorMap() && principledMaterial->baseColorMap()->sourceItem())
1866 subsceneRootItem = principledMaterial->baseColorMap()->sourceItem();
1868 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::SpecularGlossyMaterial) {
1870 const auto specularGlossyMaterial = qobject_cast<QQuick3DSpecularGlossyMaterial *>(material);
1871 if (specularGlossyMaterial) {
1873 if (specularGlossyMaterial->albedoMap() && specularGlossyMaterial->albedoMap()->sourceItem())
1874 subsceneRootItem = specularGlossyMaterial->albedoMap()->sourceItem();
1876 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
1878 const auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material);
1879 if (customMaterial) {
1881 const auto &texturesInputs = customMaterial->m_dynamicTextureMaps;
1882 for (
const auto &textureInput : texturesInputs) {
1883 if (
auto texture = textureInput->texture()) {
1884 if (texture->sourceItem()) {
1885 subsceneRootItem = texture->sourceItem();
1892 return subsceneRootItem;
1897
1898
1899QQuick3DPickResult QQuick3DViewport::getNearestPickResult(
const QVarLengthArray<QSSGRenderPickResult, 20> &pickResults)
const
1901 for (
const auto &result : pickResults) {
1902 auto pickResult = processPickResult(result);
1903 if (pickResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1907 return QQuick3DPickResult();
1911
1912
1913
1914
1915
1916bool QQuick3DViewport::forwardEventToSubscenes(QPointerEvent *event,
1918 QQuick3DSceneRenderer *renderer,
1919 const QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1926 QVarLengthArray<QPointF, 16> originalScenePositions;
1927 originalScenePositions.resize(event->pointCount());
1928 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1929 originalScenePositions[pointIndex] = event->point(pointIndex).scenePosition();
1930 for (
const auto &subscene : visitedSubscenes) {
1931 QQuickItem *subsceneRoot = subscene.first;
1932 const auto &subsceneInfo = subscene.second;
1933 Q_ASSERT(subsceneInfo.eventPointScenePositions.size() == event->pointCount());
1934 auto da = QQuickItemPrivate::get(subsceneRoot)->deliveryAgent();
1935 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1936 const auto &pt = subsceneInfo.eventPointScenePositions.at(pointIndex);
1941 QEventPoint &ep = event->point(pointIndex);
1942 QMutableEventPoint::setPosition(ep, pt);
1943 QMutableEventPoint::setScenePosition(ep, pt);
1946 if (event->isBeginEvent())
1947 da->setSceneTransform(
nullptr);
1948 if (da->event(event)) {
1950 if (QQuickDeliveryAgentPrivate::anyPointGrabbed(event) && !useRayPicking) {
1955 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(subsceneInfo.obj);
1956 const bool item2Dcase = (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D);
1957 ViewportTransformHelper *transform =
new ViewportTransformHelper;
1958 transform->viewport =
const_cast<QQuick3DViewport *>(
this);
1959 transform->renderer = renderer;
1960 transform->sceneParentNode =
static_cast<QSSGRenderNode*>(frontendObjectPrivate->spatialNode);
1961 transform->targetItem = subsceneRoot;
1962 transform->scaleX = window()->effectiveDevicePixelRatio() * m_widthMultiplier;
1963 transform->scaleY = window()->effectiveDevicePixelRatio() * m_heightMultiplier;
1964 transform->uvCoordsArePixels = item2Dcase;
1965 transform->setOnDeliveryAgent(da);
1966 qCDebug(lcPick) << event->type() <<
"created ViewportTransformHelper on" << da;
1968 }
else if (event->type() != QEvent::HoverMove) {
1969 qCDebug(lcPick) << subsceneRoot <<
"didn't want" << event;
1971 event->setAccepted(
false);
1973 if (visitedSubscenes.isEmpty()) {
1974 event->setAccepted(
false);
1976 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1977 QMutableEventPoint::setScenePosition(event->point(pointIndex), originalScenePositions.at(pointIndex));
1983 if (event->isEndEvent() && useRayPicking) {
1984 if (event->isSinglePointEvent()) {
1985 if (
static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
1986 auto &firstPt = event->point(0);
1987 event->setExclusiveGrabber(firstPt,
nullptr);
1988 event->clearPassiveGrabbers(firstPt);
1991 for (
auto &point : event->points()) {
1992 if (point.state() == QEventPoint::State::Released) {
1993 event->setExclusiveGrabber(point,
nullptr);
1994 event->clearPassiveGrabbers(point);
2004bool QQuick3DViewport::internalPick(QPointerEvent *event,
const QVector3D &origin,
const QVector3D &direction)
const
2006 QQuick3DSceneRenderer *renderer = getRenderer();
2007 if (!renderer || !event)
2010 QFlatMap<QQuickItem*, SubsceneInfo> visitedSubscenes;
2011 const bool useRayPicking = !direction.isNull();
2013 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
2014 auto &eventPoint = event->point(pointIndex);
2015 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2016 if (Q_UNLIKELY(useRayPicking))
2017 pickResults = getPickResults(renderer, origin, direction);
2019 pickResults = getPickResults(renderer, eventPoint);
2021 if (!pickResults.isEmpty())
2022 for (
const auto &pickResult : pickResults)
2023 processPickedObject(pickResult, pointIndex, event, visitedSubscenes);
2025 eventPoint.setAccepted(
false);
2028 return forwardEventToSubscenes(event, useRayPicking, renderer, visitedSubscenes);
2031bool QQuick3DViewport::singlePointPick(QSinglePointEvent *event,
const QVector3D &origin,
const QVector3D &direction)
2033 QQuick3DSceneRenderer *renderer = getRenderer();
2034 if (!renderer || !event)
2037 QSSGRenderRay ray(origin, direction);
2039 Q_ASSERT(event->pointCount() == 1);
2040 QPointF originalPosition = event->point(0).scenePosition();
2042 auto pickResults = renderer->syncPickAll(ray);
2044 bool delivered =
false;
2046 constexpr float jitterLimit = 2.5;
2047 bool withinJitterLimit =
false;
2049 for (
const auto &pickResult : pickResults) {
2050 auto [item, position] = getItemAndPosition(pickResult);
2053 if (item == m_prevMouseItem && (position - m_prevMousePos).manhattanLength() < jitterLimit && !event->button()) {
2054 withinJitterLimit =
true;
2057 auto da = QQuickItemPrivate::get(item)->deliveryAgent();
2058 QEventPoint &ep = event->point(0);
2059 QMutableEventPoint::setPosition(ep, position);
2060 QMutableEventPoint::setScenePosition(ep, position);
2061 if (da->event(event)) {
2063 if (event->type() == QEvent::MouseButtonPress) {
2064 m_prevMouseItem = item;
2065 m_prevMousePos = position;
2066 withinJitterLimit =
true;
2072 QMutableEventPoint::setScenePosition(event->point(0), originalPosition);
2073 if (!withinJitterLimit)
2074 m_prevMouseItem =
nullptr;
2079 if (event->isEndEvent()) {
2080 if (event->buttons() == Qt::NoButton) {
2081 auto &firstPt = event->point(0);
2082 event->setExclusiveGrabber(firstPt,
nullptr);
2083 event->clearPassiveGrabbers(firstPt);
2090QPair<QQuickItem *, QPointF> QQuick3DViewport::getItemAndPosition(
const QSSGRenderPickResult &pickResult)
const
2092 QQuickItem *subsceneRootItem =
nullptr;
2093 QPointF subscenePosition;
2094 const auto backendObject = pickResult.m_hitObject;
2095 const auto frontendObject = findFrontendNode(backendObject);
2096 if (!frontendObject)
2098 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
2099 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
2102 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
2104 subsceneRootItem = item2D->contentItem();
2105 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
2109 subscenePosition = pickResult.m_localUVCoords.toPointF();
2113 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
2115 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
2117 int materialSubset = pickResult.m_subset;
2118 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
2120 if (backendModel->materials.size() < (pickResult.m_subset + 1))
2121 materialSubset = backendModel->materials.size() - 1;
2122 if (materialSubset < 0)
2124 const auto backendMaterial = backendModel->materials.at(materialSubset);
2125 const auto frontendMaterial =
static_cast<QQuick3DMaterial *>(findFrontendNode(backendMaterial));
2126 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
2128 if (subsceneRootItem) {
2130 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
2131 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
2134 return {subsceneRootItem, subscenePosition};
2137QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
2138 const QVector3D &origin,
2139 const QVector3D &direction)
const
2141 const QSSGRenderRay ray(origin, direction);
2142 return renderer->syncPickAll(ray);
2145QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
const QEventPoint &eventPoint)
const
2147 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2148 QPointF realPosition = eventPoint.position() * window()->effectiveDevicePixelRatio();
2150 realPosition.rx() *= m_widthMultiplier;
2151 realPosition.ry() *= m_heightMultiplier;
2152 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(realPosition);
2153 if (rayResult.has_value())
2154 pickResults = renderer->syncPickAll(rayResult.value());
2159
2160
2161
2162
2163
2164QQuick3DObject *QQuick3DViewport::findFrontendNode(
const QSSGRenderGraphObject *backendObject)
const
2169 const auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2170 QQuick3DObject *frontendObject = sceneManager->lookUpNode(backendObject);
2171 if (!frontendObject && m_importScene) {
2172 const auto importSceneManager = QQuick3DObjectPrivate::get(m_importScene)->sceneManager;
2173 frontendObject = importSceneManager->lookUpNode(backendObject);
2175 return frontendObject;
2178QQuick3DPickResult QQuick3DViewport::processPickResult(
const QSSGRenderPickResult &pickResult)
const
2180 if (!pickResult.m_hitObject)
2181 return QQuick3DPickResult();
2183 QQuick3DObject *frontendObject = findFrontendNode(pickResult.m_hitObject);
2185 QQuick3DModel *model = qobject_cast<QQuick3DModel *>(frontendObject);
2187 auto itemAndPosition = getItemAndPosition(pickResult);
2188 return QQuick3DPickResult(model,
2189 ::sqrtf(pickResult.m_distanceSq),
2190 pickResult.m_localUVCoords,
2191 pickResult.m_scenePosition,
2192 pickResult.m_localPosition,
2193 pickResult.m_faceNormal,
2194 pickResult.m_sceneNormal,
2195 pickResult.m_instanceIndex,
2196 itemAndPosition.first);
2199 QQuick3DItem2D *frontend2DItem = qobject_cast<QQuick3DItem2D *>(frontendObject);
2200 if (frontend2DItem && frontend2DItem->contentItem()) {
2202 const QPointF subscenePosition = pickResult.m_localUVCoords.toPointF();
2203 const auto child = frontend2DItem->contentItem()->childAt(subscenePosition.x(), subscenePosition.y());
2205 return QQuick3DPickResult(child,
2206 ::sqrtf(pickResult.m_distanceSq),
2207 QVector2D(frontend2DItem->contentItem()->mapToItem(child, subscenePosition)),
2208 pickResult.m_scenePosition,
2209 pickResult.m_localPosition,
2210 pickResult.m_faceNormal);
2214 return QQuick3DPickResult();
2219QQuick3DSceneManager *QQuick3DViewport::findChildSceneManager(QQuick3DObject *inObject, QQuick3DSceneManager *manager)
2224 auto children = QQuick3DObjectPrivate::get(inObject)->childItems;
2225 for (
auto *child : std::as_const(children)) {
2226 if (
auto m = QQuick3DObjectPrivate::get(child)->sceneManager) {
2230 manager = findChildSceneManager(child, manager);
2235void QQuick3DViewport::updateInputProcessing()
2238 setAcceptTouchEvents(m_enableInputProcessing);
2239 setAcceptHoverEvents(m_enableInputProcessing);
2240 setAcceptedMouseButtons(m_enableInputProcessing ? Qt::AllButtons : Qt::NoButton);
2243void QQuick3DViewport::onReleaseCachedResources()
2245 if (
auto renderer = getRenderer())
2246 renderer->releaseCachedResources();
2250
2251
2252
2253
2254
2255
2256QQmlListProperty<QQuick3DObject> QQuick3DViewport::extensions()
2258 return QQmlListProperty<QQuick3DObject>{
this,
2259 &m_extensionListDirty,
2260 &QQuick3DExtensionListHelper::extensionAppend,
2261 &QQuick3DExtensionListHelper::extensionCount,
2262 &QQuick3DExtensionListHelper::extensionAt,
2263 &QQuick3DExtensionListHelper::extensionClear,
2264 &QQuick3DExtensionListHelper::extensionReplace,
2265 &QQuick3DExtensionListHelper::extensionRemoveLast};
2269
2270
2271void QQuick3DViewport::rebuildExtensionList()
2273 m_extensionListDirty =
true;
2278
2279
2280
2281
2282
2283QQuick3DViewport::QQuick3DViewport(PrivateInstanceType type, QQuickItem *parent)
2284 : QQuick3DViewport(parent)
2286 m_isXrViewInstance = type == PrivateInstanceType::XrViewInstance;
2289void QQuick3DViewport::updateCameraForLayer(
const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode)
2291 layerNode.explicitCameras.clear();
2292 if (!view3D.m_multiViewCameras.isEmpty()) {
2293 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
2294 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
2295 }
else if (view3D.camera()) {
2296 if (QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode))
2297 layerNode.explicitCameras.append(camera);
2302 for (QSSGRenderCamera *camera : std::as_const(layerNode.explicitCameras)) {
2303 if (!camera->parent)
2304 layerNode.addChild(*camera);
2308void QQuick3DViewport::updateSceneManagerForImportScene()
2310 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2311 if (!privateObject->sceneManager) {
2313 QQuick3DSceneManager *manager = findChildSceneManager(m_importScene);
2316 manager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2318 manager->setWindow(window());
2319 privateObject->refSceneManager(*manager);
2324 if (!privateObject->sceneManager)
2328 connect(privateObject->sceneManager, &QQuick3DSceneManager::needsUpdate,
2329 this, &QQuickItem::update, Qt::UniqueConnection);
2330 connect(privateObject->sceneManager, &QObject::destroyed,
2331 this, [&](QObject *) {
2332 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2333 privateObject->sceneManager =
nullptr;
2334 updateSceneManagerForImportScene();
2335 }, Qt::DirectConnection);
2337 QQuick3DNode *scene = m_importScene;
2339 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
2340 scene = rn ? rn->view3D()->importScene() :
nullptr;
2343 connect(QQuick3DObjectPrivate::get(scene)->sceneManager,
2344 &QQuick3DSceneManager::needsUpdate,
2345 this, &QQuickItem::update, Qt::UniqueConnection);
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2365QQuick3DViewport::RenderOverrides QQuick3DViewport::renderOverrides()
const
2367 return m_renderOverrides;
2370void QQuick3DViewport::setRenderOverrides(RenderOverrides newRenderOverrides)
2372 if (m_renderOverrides == newRenderOverrides)
2374 m_renderOverrides = newRenderOverrides;
2375 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)