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()
1591QQuick3DSceneRenderer *QQuick3DViewport::getRenderer()
const
1593 QQuick3DSceneRenderer *renderer =
nullptr;
1595 renderer = m_node->renderer;
1596 }
else if (m_renderNode) {
1597 renderer = m_renderNode->renderer;
1598 }
else if (m_directRenderer) {
1599 renderer = m_directRenderer->renderer();
1604void QQuick3DViewport::updateDynamicTextures()
1609 const auto &sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
1610 for (
auto *texture : std::as_const(sceneManager->qsgDynamicTextures))
1611 texture->updateTexture();
1613 QQuick3DNode *scene = m_importScene;
1615 const auto &importSm = QQuick3DObjectPrivate::get(scene)->sceneManager;
1616 if (importSm != sceneManager) {
1617 for (
auto *texture : std::as_const(importSm->qsgDynamicTextures))
1618 texture->updateTexture();
1622 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
1623 scene = rn ? rn->view3D()->importScene() :
nullptr;
1627QSGNode *QQuick3DViewport::setupOffscreenRenderer(QSGNode *node)
1629 SGFramebufferObjectNode *n =
static_cast<SGFramebufferObjectNode *>(node);
1633 m_node =
new SGFramebufferObjectNode;
1638 n->window = window();
1639 n->renderer = createRenderer();
1642 n->renderer->fboNode = n;
1644 connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
1647 const qreal dpr = window()->effectiveDevicePixelRatio();
1648 const QSize minFboSize = QQuickItemPrivate::get(
this)->sceneGraphContext()->minimumFBOSize();
1649 QSize desiredFboSize = QSize(m_explicitTextureWidth, m_explicitTextureHeight);
1650 if (desiredFboSize.isEmpty()) {
1651 desiredFboSize = QSize(width(), height()) * dpr;
1652 n->devicePixelRatio = dpr;
1654 m_widthMultiplier = 1.0f;
1655 m_heightMultiplier = 1.0f;
1657 QSize itemPixelSize = QSize(width(), height()) * dpr;
1659 m_widthMultiplier = desiredFboSize.width() /
float(itemPixelSize.width());
1660 m_heightMultiplier = desiredFboSize.height() /
float(itemPixelSize.height());
1661 n->devicePixelRatio = 1.0;
1663 desiredFboSize.setWidth(qMax(minFboSize.width(), desiredFboSize.width()));
1664 desiredFboSize.setHeight(qMax(minFboSize.height(), desiredFboSize.height()));
1666 if (desiredFboSize != m_effectiveTextureSize) {
1667 m_effectiveTextureSize = desiredFboSize;
1668 emit effectiveTextureSizeChanged();
1671 n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1672 n->setRect(0, 0, width(), height());
1673 if (checkIsVisible() && isComponentComplete()) {
1674 n->renderer->synchronize(
this, desiredFboSize, n->devicePixelRatio);
1675 if (n->renderer->m_textureNeedsFlip)
1676 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
1677 updateDynamicTextures();
1678 n->scheduleRender();
1684QSGNode *QQuick3DViewport::setupInlineRenderer(QSGNode *node)
1686 QQuick3DSGRenderNode *n =
static_cast<QQuick3DSGRenderNode *>(node);
1689 m_renderNode =
new QQuick3DSGRenderNode;
1694 n->window = window();
1695 n->renderer = createRenderer();
1700 if (!m_effectiveTextureSize.isEmpty()) {
1701 m_effectiveTextureSize = QSize();
1702 emit effectiveTextureSizeChanged();
1705 const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
1710 if (checkIsVisible() && isComponentComplete()) {
1711 n->renderer->synchronize(
this, targetSize, window()->effectiveDevicePixelRatio());
1712 updateDynamicTextures();
1713 n->markDirty(QSGNode::DirtyMaterial);
1720void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
1722 auto renderMode = (mode == Underlay) ? QQuick3DSGDirectRenderer::Underlay
1723 : QQuick3DSGDirectRenderer::Overlay;
1724 if (!m_directRenderer) {
1725 QQuick3DSceneRenderer *sceneRenderer = createRenderer();
1728 m_directRenderer =
new QQuick3DSGDirectRenderer(sceneRenderer, window(), renderMode);
1729 connect(window(), &QQuickWindow::sceneGraphInvalidated,
this, &QQuick3DViewport::cleanupDirectRenderer, Qt::DirectConnection);
1732 if (!m_effectiveTextureSize.isEmpty()) {
1733 m_effectiveTextureSize = QSize();
1734 emit effectiveTextureSizeChanged();
1737 const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
1738 m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
1739 m_directRenderer->setVisibility(isVisible());
1741 m_directRenderer->preSynchronize();
1742 m_directRenderer->renderer()->synchronize(
this, targetSize.toSize(), window()->effectiveDevicePixelRatio());
1743 updateDynamicTextures();
1744 m_directRenderer->requestRender();
1750bool QQuick3DViewport::checkIsVisible()
const
1752 auto childPrivate = QQuickItemPrivate::get(
this);
1753 return (childPrivate->explicitVisible ||
1754 (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
1759
1760
1761
1762
1763
1764
1765
1766
1767void QQuick3DViewport::processPickedObject(
const QSSGRenderPickResult &pickResult,
1769 QPointerEvent *event,
1770 QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1772 QQuickItem *subsceneRootItem =
nullptr;
1773 QPointF subscenePosition;
1774 const auto backendObject = pickResult.m_hitObject;
1775 const auto frontendObject = findFrontendNode(backendObject);
1776 if (!frontendObject)
1782 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1783 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1786 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1788 subsceneRootItem = item2D->contentItem();
1789 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1793 subscenePosition = pickResult.m_localUVCoords.toPointF();
1797 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1799 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1801 int materialSubset = pickResult.m_subset;
1802 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1804 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1805 materialSubset = backendModel->materials.size() - 1;
1806 if (materialSubset < 0)
1808 const auto backendMaterial = backendModel->materials.at(materialSubset);
1809 const auto frontendMaterial =
static_cast<QQuick3DMaterial*>(findFrontendNode(backendMaterial));
1810 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1812 if (subsceneRootItem) {
1814 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1815 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1820 if (subsceneRootItem) {
1821 SubsceneInfo &subscene = visitedSubscenes[subsceneRootItem];
1822 subscene.obj = frontendObject;
1823 if (subscene.eventPointScenePositions.size() != event->pointCount()) {
1825 constexpr QPointF inf(-qt_inf(), -qt_inf());
1826 subscene.eventPointScenePositions.resize(event->pointCount(), inf);
1828 subscene.eventPointScenePositions[pointIndex] = subscenePosition;
1833
1834
1835
1836
1837
1838
1839
1840
1842QQuickItem *QQuick3DViewport::getSubSceneRootItem(QQuick3DMaterial *material)
const
1847 QQuickItem *subsceneRootItem =
nullptr;
1848 const auto frontendMaterialPrivate = QQuick3DObjectPrivate::get(material);
1850 if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::DefaultMaterial) {
1852 const auto defaultMaterial = qobject_cast<QQuick3DDefaultMaterial *>(material);
1853 if (defaultMaterial) {
1855 if (defaultMaterial->diffuseMap() && defaultMaterial->diffuseMap()->sourceItem())
1856 subsceneRootItem = defaultMaterial->diffuseMap()->sourceItem();
1859 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::PrincipledMaterial) {
1861 const auto principledMaterial = qobject_cast<QQuick3DPrincipledMaterial *>(material);
1862 if (principledMaterial) {
1864 if (principledMaterial->baseColorMap() && principledMaterial->baseColorMap()->sourceItem())
1865 subsceneRootItem = principledMaterial->baseColorMap()->sourceItem();
1867 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::SpecularGlossyMaterial) {
1869 const auto specularGlossyMaterial = qobject_cast<QQuick3DSpecularGlossyMaterial *>(material);
1870 if (specularGlossyMaterial) {
1872 if (specularGlossyMaterial->albedoMap() && specularGlossyMaterial->albedoMap()->sourceItem())
1873 subsceneRootItem = specularGlossyMaterial->albedoMap()->sourceItem();
1875 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
1877 const auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material);
1878 if (customMaterial) {
1880 const auto &texturesInputs = customMaterial->m_dynamicTextureMaps;
1881 for (
const auto &textureInput : texturesInputs) {
1882 if (
auto texture = textureInput->texture()) {
1883 if (texture->sourceItem()) {
1884 subsceneRootItem = texture->sourceItem();
1891 return subsceneRootItem;
1896
1897
1898QQuick3DPickResult QQuick3DViewport::getNearestPickResult(
const QVarLengthArray<QSSGRenderPickResult, 20> &pickResults)
const
1900 for (
const auto &result : pickResults) {
1901 auto pickResult = processPickResult(result);
1902 if (pickResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1906 return QQuick3DPickResult();
1910
1911
1912
1913
1914
1915bool QQuick3DViewport::forwardEventToSubscenes(QPointerEvent *event,
1917 QQuick3DSceneRenderer *renderer,
1918 const QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1925 QVarLengthArray<QPointF, 16> originalScenePositions;
1926 originalScenePositions.resize(event->pointCount());
1927 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1928 originalScenePositions[pointIndex] = event->point(pointIndex).scenePosition();
1929 for (
const auto &subscene : visitedSubscenes) {
1930 QQuickItem *subsceneRoot = subscene.first;
1931 const auto &subsceneInfo = subscene.second;
1932 Q_ASSERT(subsceneInfo.eventPointScenePositions.size() == event->pointCount());
1933 auto da = QQuickItemPrivate::get(subsceneRoot)->deliveryAgent();
1934 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1935 const auto &pt = subsceneInfo.eventPointScenePositions.at(pointIndex);
1940 QEventPoint &ep = event->point(pointIndex);
1941 QMutableEventPoint::setPosition(ep, pt);
1942 QMutableEventPoint::setScenePosition(ep, pt);
1945 if (event->isBeginEvent())
1946 da->setSceneTransform(
nullptr);
1947 if (da->event(event)) {
1949 if (QQuickDeliveryAgentPrivate::anyPointGrabbed(event) && !useRayPicking) {
1954 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(subsceneInfo.obj);
1955 const bool item2Dcase = (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D);
1956 ViewportTransformHelper *transform =
new ViewportTransformHelper;
1957 transform->viewport =
const_cast<QQuick3DViewport *>(
this);
1958 transform->renderer = renderer;
1959 transform->sceneParentNode =
static_cast<QSSGRenderNode*>(frontendObjectPrivate->spatialNode);
1960 transform->targetItem = subsceneRoot;
1961 transform->scaleX = window()->effectiveDevicePixelRatio() * m_widthMultiplier;
1962 transform->scaleY = window()->effectiveDevicePixelRatio() * m_heightMultiplier;
1963 transform->uvCoordsArePixels = item2Dcase;
1964 transform->setOnDeliveryAgent(da);
1965 qCDebug(lcPick) << event->type() <<
"created ViewportTransformHelper on" << da;
1967 }
else if (event->type() != QEvent::HoverMove) {
1968 qCDebug(lcPick) << subsceneRoot <<
"didn't want" << event;
1970 event->setAccepted(
false);
1972 if (visitedSubscenes.isEmpty()) {
1973 event->setAccepted(
false);
1975 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1976 QMutableEventPoint::setScenePosition(event->point(pointIndex), originalScenePositions.at(pointIndex));
1982 if (event->isEndEvent() && useRayPicking) {
1983 if (event->isSinglePointEvent()) {
1984 if (
static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
1985 auto &firstPt = event->point(0);
1986 event->setExclusiveGrabber(firstPt,
nullptr);
1987 event->clearPassiveGrabbers(firstPt);
1990 for (
auto &point : event->points()) {
1991 if (point.state() == QEventPoint::State::Released) {
1992 event->setExclusiveGrabber(point,
nullptr);
1993 event->clearPassiveGrabbers(point);
2003bool QQuick3DViewport::internalPick(QPointerEvent *event,
const QVector3D &origin,
const QVector3D &direction)
const
2005 QQuick3DSceneRenderer *renderer = getRenderer();
2006 if (!renderer || !event)
2009 QFlatMap<QQuickItem*, SubsceneInfo> visitedSubscenes;
2010 const bool useRayPicking = !direction.isNull();
2012 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
2013 auto &eventPoint = event->point(pointIndex);
2014 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2015 if (Q_UNLIKELY(useRayPicking))
2016 pickResults = getPickResults(renderer, origin, direction);
2018 pickResults = getPickResults(renderer, eventPoint);
2020 if (!pickResults.isEmpty())
2021 for (
const auto &pickResult : pickResults)
2022 processPickedObject(pickResult, pointIndex, event, visitedSubscenes);
2024 eventPoint.setAccepted(
false);
2027 return forwardEventToSubscenes(event, useRayPicking, renderer, visitedSubscenes);
2030bool QQuick3DViewport::singlePointPick(QSinglePointEvent *event,
const QVector3D &origin,
const QVector3D &direction)
2032 QQuick3DSceneRenderer *renderer = getRenderer();
2033 if (!renderer || !event)
2036 QSSGRenderRay ray(origin, direction);
2038 Q_ASSERT(event->pointCount() == 1);
2039 QPointF originalPosition = event->point(0).scenePosition();
2041 auto pickResults = renderer->syncPickAll(ray);
2043 bool delivered =
false;
2045 constexpr float jitterLimit = 2.5;
2046 bool withinJitterLimit =
false;
2048 for (
const auto &pickResult : pickResults) {
2049 auto [item, position] = getItemAndPosition(pickResult);
2052 if (item == m_prevMouseItem && (position - m_prevMousePos).manhattanLength() < jitterLimit && !event->button()) {
2053 withinJitterLimit =
true;
2056 auto da = QQuickItemPrivate::get(item)->deliveryAgent();
2057 QEventPoint &ep = event->point(0);
2058 QMutableEventPoint::setPosition(ep, position);
2059 QMutableEventPoint::setScenePosition(ep, position);
2060 if (da->event(event)) {
2062 if (event->type() == QEvent::MouseButtonPress) {
2063 m_prevMouseItem = item;
2064 m_prevMousePos = position;
2065 withinJitterLimit =
true;
2071 QMutableEventPoint::setScenePosition(event->point(0), originalPosition);
2072 if (!withinJitterLimit)
2073 m_prevMouseItem =
nullptr;
2078 if (event->isEndEvent()) {
2079 if (event->buttons() == Qt::NoButton) {
2080 auto &firstPt = event->point(0);
2081 event->setExclusiveGrabber(firstPt,
nullptr);
2082 event->clearPassiveGrabbers(firstPt);
2089QPair<QQuickItem *, QPointF> QQuick3DViewport::getItemAndPosition(
const QSSGRenderPickResult &pickResult)
const
2091 QQuickItem *subsceneRootItem =
nullptr;
2092 QPointF subscenePosition;
2093 const auto backendObject = pickResult.m_hitObject;
2094 const auto frontendObject = findFrontendNode(backendObject);
2095 if (!frontendObject)
2097 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
2098 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
2101 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
2103 subsceneRootItem = item2D->contentItem();
2104 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
2108 subscenePosition = pickResult.m_localUVCoords.toPointF();
2112 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
2114 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
2116 int materialSubset = pickResult.m_subset;
2117 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
2119 if (backendModel->materials.size() < (pickResult.m_subset + 1))
2120 materialSubset = backendModel->materials.size() - 1;
2121 if (materialSubset < 0)
2123 const auto backendMaterial = backendModel->materials.at(materialSubset);
2124 const auto frontendMaterial =
static_cast<QQuick3DMaterial *>(findFrontendNode(backendMaterial));
2125 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
2127 if (subsceneRootItem) {
2129 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
2130 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
2133 return {subsceneRootItem, subscenePosition};
2136QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
2137 const QVector3D &origin,
2138 const QVector3D &direction)
const
2140 const QSSGRenderRay ray(origin, direction);
2141 return renderer->syncPickAll(ray);
2144QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
const QEventPoint &eventPoint)
const
2146 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2147 QPointF realPosition = eventPoint.position() * window()->effectiveDevicePixelRatio();
2149 realPosition.rx() *= m_widthMultiplier;
2150 realPosition.ry() *= m_heightMultiplier;
2151 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(realPosition);
2152 if (rayResult.has_value())
2153 pickResults = renderer->syncPickAll(rayResult.value());
2158
2159
2160
2161
2162
2163QQuick3DObject *QQuick3DViewport::findFrontendNode(
const QSSGRenderGraphObject *backendObject)
const
2168 const auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2169 QQuick3DObject *frontendObject = sceneManager->lookUpNode(backendObject);
2170 if (!frontendObject && m_importScene) {
2171 const auto importSceneManager = QQuick3DObjectPrivate::get(m_importScene)->sceneManager;
2172 frontendObject = importSceneManager->lookUpNode(backendObject);
2174 return frontendObject;
2177QQuick3DPickResult QQuick3DViewport::processPickResult(
const QSSGRenderPickResult &pickResult)
const
2179 if (!pickResult.m_hitObject)
2180 return QQuick3DPickResult();
2182 QQuick3DObject *frontendObject = findFrontendNode(pickResult.m_hitObject);
2184 QQuick3DModel *model = qobject_cast<QQuick3DModel *>(frontendObject);
2186 auto itemAndPosition = getItemAndPosition(pickResult);
2187 return QQuick3DPickResult(model,
2188 ::sqrtf(pickResult.m_distanceSq),
2189 pickResult.m_localUVCoords,
2190 pickResult.m_scenePosition,
2191 pickResult.m_localPosition,
2192 pickResult.m_faceNormal,
2193 pickResult.m_sceneNormal,
2194 pickResult.m_instanceIndex,
2195 itemAndPosition.first);
2198 QQuick3DItem2D *frontend2DItem = qobject_cast<QQuick3DItem2D *>(frontendObject);
2199 if (frontend2DItem && frontend2DItem->contentItem()) {
2201 const QPointF subscenePosition = pickResult.m_localUVCoords.toPointF();
2202 const auto child = frontend2DItem->contentItem()->childAt(subscenePosition.x(), subscenePosition.y());
2204 return QQuick3DPickResult(child,
2205 ::sqrtf(pickResult.m_distanceSq),
2206 QVector2D(frontend2DItem->contentItem()->mapToItem(child, subscenePosition)),
2207 pickResult.m_scenePosition,
2208 pickResult.m_localPosition,
2209 pickResult.m_faceNormal);
2213 return QQuick3DPickResult();
2218QQuick3DSceneManager *QQuick3DViewport::findChildSceneManager(QQuick3DObject *inObject, QQuick3DSceneManager *manager)
2223 auto children = QQuick3DObjectPrivate::get(inObject)->childItems;
2224 for (
auto *child : std::as_const(children)) {
2225 if (
auto m = QQuick3DObjectPrivate::get(child)->sceneManager) {
2229 manager = findChildSceneManager(child, manager);
2234void QQuick3DViewport::updateInputProcessing()
2237 setAcceptTouchEvents(m_enableInputProcessing);
2238 setAcceptHoverEvents(m_enableInputProcessing);
2239 setAcceptedMouseButtons(m_enableInputProcessing ? Qt::AllButtons : Qt::NoButton);
2242void QQuick3DViewport::onReleaseCachedResources()
2244 if (
auto renderer = getRenderer())
2245 renderer->releaseCachedResources();
2249
2250
2251
2252
2253
2254
2255QQmlListProperty<QQuick3DObject> QQuick3DViewport::extensions()
2257 return QQmlListProperty<QQuick3DObject>{
this,
2258 &m_extensionListDirty,
2259 &QQuick3DExtensionListHelper::extensionAppend,
2260 &QQuick3DExtensionListHelper::extensionCount,
2261 &QQuick3DExtensionListHelper::extensionAt,
2262 &QQuick3DExtensionListHelper::extensionClear,
2263 &QQuick3DExtensionListHelper::extensionReplace,
2264 &QQuick3DExtensionListHelper::extensionRemoveLast};
2268
2269
2270void QQuick3DViewport::rebuildExtensionList()
2272 m_extensionListDirty =
true;
2277
2278
2279
2280
2281
2282QQuick3DViewport::QQuick3DViewport(PrivateInstanceType type, QQuickItem *parent)
2283 : QQuick3DViewport(parent)
2285 m_isXrViewInstance = type == PrivateInstanceType::XrViewInstance;
2288void QQuick3DViewport::updateCameraForLayer(
const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode)
2290 layerNode.explicitCameras.clear();
2291 if (!view3D.m_multiViewCameras.isEmpty()) {
2292 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
2293 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
2294 }
else if (view3D.camera()) {
2295 if (QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode))
2296 layerNode.explicitCameras.append(camera);
2301 for (QSSGRenderCamera *camera : std::as_const(layerNode.explicitCameras)) {
2302 if (!camera->parent)
2303 layerNode.addChild(*camera);
2307void QQuick3DViewport::updateSceneManagerForImportScene()
2309 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2310 if (!privateObject->sceneManager) {
2312 QQuick3DSceneManager *manager = findChildSceneManager(m_importScene);
2315 manager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2317 manager->setWindow(window());
2318 privateObject->refSceneManager(*manager);
2323 if (!privateObject->sceneManager)
2327 connect(privateObject->sceneManager, &QQuick3DSceneManager::needsUpdate,
2328 this, &QQuickItem::update, Qt::UniqueConnection);
2329 connect(privateObject->sceneManager, &QObject::destroyed,
2330 this, [&](QObject *) {
2331 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2332 privateObject->sceneManager =
nullptr;
2333 updateSceneManagerForImportScene();
2334 }, Qt::DirectConnection);
2336 QQuick3DNode *scene = m_importScene;
2338 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
2339 scene = rn ? rn->view3D()->importScene() :
nullptr;
2342 connect(QQuick3DObjectPrivate::get(scene)->sceneManager,
2343 &QQuick3DSceneManager::needsUpdate,
2344 this, &QQuickItem::update, Qt::UniqueConnection);
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2363QQuick3DViewport::RenderOverrides QQuick3DViewport::renderOverrides()
const
2365 return m_renderOverrides;
2368void QQuick3DViewport::setRenderOverrides(RenderOverrides newRenderOverrides)
2370 if (m_renderOverrides == newRenderOverrides)
2372 m_renderOverrides = newRenderOverrides;
2373 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)