19#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
20#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
22#include <QtQuick3DUtils/private/qssgassert_p.h>
24#include <qsgtextureprovider.h>
25#include <QSGSimpleTextureNode>
26#include <QSGRendererInterface>
27#include <QQuickWindow>
28#include <QtQuick/private/qquickitem_p.h>
29#include <QtQuick/private/qquickpointerhandler_p.h>
33#include <QtGui/private/qeventpoint_p.h>
35#include <QtCore/private/qnumeric_p.h>
36#include <QtCore/qpointer.h>
42Q_STATIC_LOGGING_CATEGORY(lcEv,
"qt.quick3d.event")
43Q_STATIC_LOGGING_CATEGORY(lcPick,
"qt.quick3d.pick")
45static bool isforceInputHandlingSet()
47 static const bool v = (qEnvironmentVariableIntValue(
"QT_QUICK3D_FORCE_INPUT_HANDLING") > 0);
54 for (
auto o : owners) {
56 o->setSceneTransform(
nullptr);
62 da->setSceneTransform(
this);
67
68
69
70
71
73 QPointF point = viewportPoint;
78 point = viewport->mapFromScene(viewportPoint);
81 std::optional<QSSGRenderRay> rayResult =
renderer->getRayFromViewportPos(point);
82 if (rayResult.has_value()) {
84 if (!pickResults.isEmpty()) {
85 const auto pickResult = pickResults.first();
86 auto ret = pickResult.m_localUVCoords.toPointF();
88 ret = QPointF(targetItem->x() + ret.x() * targetItem->width(),
89 targetItem->y() - ret.y() * targetItem->height() + targetItem->height());
91 const bool outOfModel = pickResult.m_localUVCoords.isNull();
92 qCDebug(lcEv) << viewportPoint <<
"->" << (outOfModel ?
"OOM" :
"") << ret <<
"@" << pickResult.m_scenePosition
93 <<
"UV" << pickResult.m_localUVCoords <<
"dist" << qSqrt(pickResult.m_distanceSq);
95 return lastGoodMapping;
97 lastGoodMapping = ret;
123 static void extensionAppend(QQmlListProperty<QQuick3DObject> *list, QQuick3DObject *extension)
125 QSSG_ASSERT(list && extension,
return);
127 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
128 if (
const auto idx = that->m_extensions.indexOf(extension); idx == -1) {
129 if (!extension->parentItem())
130 extension->setParentItem(that->m_sceneRoot);
131 that->m_extensions.push_back(extension);
132 that->m_extensionListDirty =
true;
138 QQuick3DObject *ret =
nullptr;
139 QSSG_ASSERT(list,
return ret);
141 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
142 if (that->m_extensions.size() > index)
143 ret = that->m_extensions.at(index);
151 QSSG_ASSERT(list,
return ret);
153 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object))
154 ret = that->m_extensions.size();
160 QSSG_ASSERT(list,
return);
162 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
163 that->m_extensions.clear();
164 that->m_extensionListDirty =
true;
167 static void extensionReplace(QQmlListProperty<QQuick3DObject> *list, qsizetype idx, QQuick3DObject *o)
169 QSSG_ASSERT(list,
return);
171 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
172 if (that->m_extensions.size() > idx && idx > -1) {
173 that->m_extensions.replace(idx, o);
174 that->m_extensionListDirty =
true;
180 QSSG_ASSERT(list,
return);
182 if (QQuick3DViewport *that = qobject_cast<QQuick3DViewport *>(list->object)) {
183 that->m_extensions.removeLast();
184 that->m_extensionListDirty =
true;
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
243QQuick3DViewport::QQuick3DViewport(QQuickItem *parent)
246 setFlag(ItemHasContents);
248 m_sceneRoot =
new QQuick3DSceneRootNode(
this);
249 m_renderStats =
new QQuick3DRenderStats();
250 QQuick3DSceneManager *sceneManager =
new QQuick3DSceneManager();
251 QQuick3DObjectPrivate::get(m_sceneRoot)->refSceneManager(*sceneManager);
252 Q_ASSERT(sceneManager == QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager);
253 connect(sceneManager, &QQuick3DSceneManager::needsUpdate,
254 this, &QQuickItem::update);
258 if (isforceInputHandlingSet()) {
259 m_enableInputProcessing =
true;
260 updateInputProcessing();
265QQuick3DViewport::~QQuick3DViewport()
274 if (m_directRenderer && m_directRenderer->thread() == thread()) {
275 delete m_directRenderer;
276 m_directRenderer =
nullptr;
281 if (
auto qw = window())
282 disconnect(qw,
nullptr,
this,
nullptr);
284 auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
286 sceneManager->setParent(
nullptr);
287 if (
auto wa = sceneManager->wattached)
288 wa->queueForCleanup(sceneManager);
292 m_sceneRoot =
nullptr;
294 delete m_builtInEnvironment;
298 m_renderStats->deleteLater();
300 if (!window() && sceneManager && sceneManager->wattached)
301 QMetaObject::invokeMethod(sceneManager->wattached, &QQuick3DWindowAttachment::evaluateEol, Qt::QueuedConnection);
304static void ssgn_append(QQmlListProperty<QObject> *property, QObject *obj)
308 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
310 if (QQuick3DObject *sceneObject = qmlobject_cast<QQuick3DObject *>(obj)) {
311 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
312 itemProperty.append(&itemProperty, sceneObject);
314 QQuickItemPrivate::data_append(property, obj);
320 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
321 if (!view3d || !view3d->scene() || !QQuick3DObjectPrivate::get(view3d->scene())->data().count)
323 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
324 return itemProperty.count(&itemProperty);
329 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
330 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
331 return itemProperty.at(&itemProperty, i);
336 QQuick3DViewport *view3d =
static_cast<QQuick3DViewport *>(property->object);
337 QQmlListProperty<QObject> itemProperty = QQuick3DObjectPrivate::get(view3d->scene())->data();
338 return itemProperty.clear(&itemProperty);
342QQmlListProperty<QObject> QQuick3DViewport::data()
344 return QQmlListProperty<QObject>(
this,
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368QQuick3DCamera *QQuick3DViewport::camera()
const
374
375
376
377
378
379
380
381
382QQuick3DSceneEnvironment *QQuick3DViewport::environment()
const
384 if (!m_environment) {
385 if (!m_builtInEnvironment) {
386 m_builtInEnvironment =
new QQuick3DSceneEnvironment;
390 if (QThread::currentThread() != m_sceneRoot->thread())
391 m_builtInEnvironment->moveToThread(m_sceneRoot->thread());
392 m_builtInEnvironment->setParentItem(m_sceneRoot);
395 return m_builtInEnvironment;
398 return m_environment;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421QQuick3DNode *QQuick3DViewport::scene()
const
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453QQuick3DNode *QQuick3DViewport::importScene()
const
455 return m_importScene;
459
460
461
462
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
501QQuick3DViewport::RenderMode QQuick3DViewport::renderMode()
const
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527#if QT_CONFIG(quick_shadereffect)
528QQuickShaderEffectSource::Format QQuick3DViewport::renderFormat()
const
530 return m_renderFormat;
535
536
537
538
539
540
541
542
543QQuick3DRenderStats *QQuick3DViewport::renderStats()
const
545 return m_renderStats;
548QQuick3DSceneRenderer *QQuick3DViewport::createRenderer()
const
550 QQuick3DSceneRenderer *renderer =
nullptr;
552 if (QQuickWindow *qw = window()) {
553 auto wa = QQuick3DSceneManager::getOrSetWindowAttachment(*qw);
554 auto rci = wa->rci();
556 QSGRendererInterface *rif = qw->rendererInterface();
557 if (QSSG_GUARD(QSGRendererInterface::isApiRhiBased(rif->graphicsApi()))) {
558 QRhi *rhi =
static_cast<QRhi *>(rif->getResource(qw, QSGRendererInterface::RhiResource));
559 QSSG_CHECK_X(rhi !=
nullptr,
"No QRhi from QQuickWindow, this cannot happen");
569 rci = std::make_shared<QSSGRenderContextInterface>(rhi);
573 connect(wa, &QQuick3DWindowAttachment::releaseCachedResources,
this,
574 &QQuick3DViewport::onReleaseCachedResources, Qt::DirectConnection);
577 qWarning(
"The Qt Quick scene is using a rendering method that is not based on QRhi and a 3D graphics API. "
578 "Qt Quick 3D is not functional in such an environment. The View3D item is not going to display anything.");
583 renderer =
new QQuick3DSceneRenderer(rci);
584 Q_QUICK3D_PROFILE_ASSIGN_ID(
this, renderer);
591bool QQuick3DViewport::isTextureProvider()
const
594 if (m_renderMode == QQuick3DViewport::Offscreen)
600QSGTextureProvider *QQuick3DViewport::textureProvider()
const
605 if (QQuickItem::isTextureProvider())
606 return QQuickItem::textureProvider();
609 if (m_renderMode != QQuick3DViewport::Offscreen)
612 QQuickWindow *w = window();
614 qWarning(
"QSSGView3D::textureProvider: can only be queried on the rendering thread of an exposed window");
619 m_node =
new SGFramebufferObjectNode;
632void QQuick3DViewport::releaseResources()
634 if (m_directRenderer) {
635 window()->scheduleRenderJob(
new CleanupJob(m_directRenderer), QQuickWindow::BeforeSynchronizingStage);
636 m_directRenderer =
nullptr;
642void QQuick3DViewport::cleanupDirectRenderer()
644 delete m_directRenderer;
645 m_directRenderer =
nullptr;
648void QQuick3DViewport::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
650 QQuickItem::geometryChange(newGeometry, oldGeometry);
652 if (newGeometry.size() != oldGeometry.size())
656QSGNode *QQuick3DViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
659 if (m_renderModeDirty) {
664 m_renderNode =
nullptr;
666 if (m_directRenderer) {
667 delete m_directRenderer;
668 m_directRenderer =
nullptr;
672 m_renderModeDirty =
false;
674 switch (m_renderMode) {
679 setupDirectRenderer(m_renderMode);
683 node = setupOffscreenRenderer(node);
687 node = setupInlineRenderer(node);
691 if (!isforceInputHandlingSet()) {
693 const auto inputHandlingEnabled =
694 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->inputHandlingEnabled;
695 const auto enable = inputHandlingEnabled > 0;
696 if (m_enableInputProcessing != enable) {
697 m_enableInputProcessing = enable;
698 QMetaObject::invokeMethod(
this,
"updateInputProcessing", Qt::QueuedConnection);
705void QQuick3DViewport::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
707 if (change == ItemSceneChange) {
711 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->setWindow(value.window);
713 QQuick3DObjectPrivate::get(m_importScene)->sceneManager->setWindow(value.window);
714 m_renderStats->setWindow(value.window);
716 }
else if (change == ItemVisibleHasChanged && isVisible()) {
721bool QQuick3DViewport::event(QEvent *event)
723 if (m_enableInputProcessing && event->isPointerEvent())
724 return internalPick(
static_cast<QPointerEvent *>(event));
726 return QQuickItem::event(event);
729void QQuick3DViewport::componentComplete()
731 QQuickItem::componentComplete();
732 Q_QUICK3D_PROFILE_REGISTER(
this);
735void QQuick3DViewport::setCamera(QQuick3DCamera *camera)
737 if (m_camera == camera)
740 if (camera && !camera->parentItem())
741 camera->setParentItem(m_sceneRoot);
743 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
745 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setCamera, camera, m_camera);
748 emit cameraChanged();
752void QQuick3DViewport::setMultiViewCameras(QQuick3DCamera **firstCamera,
int count)
754 m_multiViewCameras.clear();
755 bool sendChangeSignal =
false;
756 for (
int i = 0; i < count; ++i) {
757 QQuick3DCamera *camera = *(firstCamera + i);
759 if (!camera->parentItem())
760 camera->setParentItem(m_sceneRoot);
761 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
764 if (m_camera != camera) {
766 sendChangeSignal =
true;
770 m_multiViewCameras.append(camera);
775 if (sendChangeSignal)
776 emit cameraChanged();
781void QQuick3DViewport::setEnvironment(QQuick3DSceneEnvironment *environment)
783 if (m_environment == environment)
786 m_environment = environment;
787 if (m_environment && !m_environment->parentItem())
788 m_environment->setParentItem(m_sceneRoot);
790 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setEnvironment, environment, m_environment);
792 emit environmentChanged();
796void QQuick3DViewport::setImportScene(QQuick3DNode *inScene)
806 QQuick3DNode *scene = inScene;
808 if (m_sceneRoot == scene) {
809 qmlWarning(
this) <<
"Cannot allow self-import or cross-import!";
813 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
814 scene = rn ? rn->view3D()->importScene() :
nullptr;
817 m_importScene = inScene;
819 updateSceneManagerForImportScene();
821 emit importSceneChanged();
825void QQuick3DViewport::setRenderMode(QQuick3DViewport::RenderMode renderMode)
827 if (m_renderMode == renderMode)
830 m_renderMode = renderMode;
831 m_renderModeDirty =
true;
832 emit renderModeChanged();
836#if QT_CONFIG(quick_shadereffect)
837void QQuick3DViewport::setRenderFormat(QQuickShaderEffectSource::Format format)
839 if (m_renderFormat == format)
842 m_renderFormat = format;
843 m_renderModeDirty =
true;
844 emit renderFormatChanged();
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868int QQuick3DViewport::explicitTextureWidth()
const
870 return m_explicitTextureWidth;
873void QQuick3DViewport::setExplicitTextureWidth(
int width)
875 if (m_explicitTextureWidth == width)
878 m_explicitTextureWidth = width;
879 emit explicitTextureWidthChanged();
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902int QQuick3DViewport::explicitTextureHeight()
const
904 return m_explicitTextureHeight;
907void QQuick3DViewport::setExplicitTextureHeight(
int height)
909 if (m_explicitTextureHeight == height)
912 m_explicitTextureHeight = height;
913 emit explicitTextureHeightChanged();
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932QSize QQuick3DViewport::effectiveTextureSize()
const
934 return m_effectiveTextureSize;
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954QVector3D QQuick3DViewport::mapFrom3DScene(
const QVector3D &scenePos)
const
957 qmlWarning(
this) <<
"Cannot resolve view position without a camera assigned!";
958 return QVector3D(0, 0, 0);
961 qreal _width = width();
962 qreal _height = height();
963 if (_width == 0 || _height == 0)
964 return QVector3D(0, 0, 0);
966 const QVector3D normalizedPos = m_camera->mapToViewport(scenePos, _width, _height);
967 return normalizedPos * QVector3D(
float(_width),
float(_height), 1);
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987QVector3D QQuick3DViewport::mapTo3DScene(
const QVector3D &viewPos)
const
990 qmlWarning(
this) <<
"Cannot resolve scene position without a camera assigned!";
991 return QVector3D(0, 0, 0);
994 qreal _width = width();
995 qreal _height = height();
996 if (_width == 0 || _height == 0)
997 return QVector3D(0, 0, 0);
999 const QVector3D normalizedPos = viewPos / QVector3D(
float(_width),
float(_height), 1);
1000 return m_camera->mapFromViewport(normalizedPos, _width, _height);
1004
1005
1006
1007
1008
1009
1010
1011QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y)
const
1013 QQuick3DSceneRenderer *renderer = getRenderer();
1015 return QQuick3DPickResult();
1017 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1018 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1019 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1020 if (!rayResult.has_value())
1021 return QQuick3DPickResult();
1023 const auto resultList = renderer->syncPick(rayResult.value());
1024 return getNearestPickResult(resultList);
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y, QQuick3DModel *model)
const
1039 QQuick3DSceneRenderer *renderer = getRenderer();
1041 return QQuick3DPickResult();
1043 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1044 qreal(y) * window()->effectiveDevicePixelRatio());
1045 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1047 if (!rayResult.has_value())
1048 return QQuick3DPickResult();
1050 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1051 const auto resultList = renderer->syncPickOne(rayResult.value(), renderNode);
1052 return getNearestPickResult(resultList);
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070QList<QQuick3DPickResult> QQuick3DViewport::pickSubset(
float x,
float y,
const QJSValue &models)
const
1072 QQuick3DSceneRenderer *renderer = getRenderer();
1076 QVarLengthArray<QSSGRenderNode*> renderNodes;
1078 if (models.isArray()) {
1079 const auto length = models.property(QStringLiteral(
"length")).toInt();
1083 for (
int i = 0; i < length; ++i) {
1084 const auto isQObject = models.property(i).isQObject();
1086 qmlWarning(
this) <<
"Type provided for picking is not a QObject. Needs to be of type QQuick3DModel.";
1089 const auto obj = models.property(i).toQObject();
1090 const auto model = qobject_cast<QQuick3DModel *>(obj);
1092 qmlWarning(
this) <<
"Type " << obj->metaObject()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1095 const auto priv = QQuick3DObjectPrivate::get(model);
1096 if (priv && priv->spatialNode) {
1097 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1102 const auto subsetVariant = models.toVariant();
1103 if (!subsetVariant.isValid() || !subsetVariant.canConvert<QQmlListReference>())
1106 const auto list = subsetVariant.value<QQmlListReference>();
1109 if (list.listElementType()->className() != QQuick3DModel::staticMetaObject.className()) {
1110 qmlWarning(
this) <<
"Type " << list.listElementType()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1113 for (
int i = 0; i < list.count(); ++i) {
1114 auto model =
static_cast<QQuick3DModel *>(list.at(i));
1117 auto priv = QQuick3DObjectPrivate::get(model);
1118 if (priv && priv->spatialNode) {
1119 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1124 if (renderNodes.empty())
1127 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1128 qreal(y) * window()->effectiveDevicePixelRatio());
1129 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1130 if (!rayResult.has_value())
1133 const auto resultList = renderer->syncPickSubset(rayResult.value(), renderNodes);
1135 QList<QQuick3DPickResult> processedResultList;
1136 processedResultList.reserve(resultList.size());
1137 for (
const auto &result : resultList)
1138 processedResultList.append(processPickResult(result));
1140 return processedResultList;
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155QList<QQuick3DPickResult> QQuick3DViewport::pickAll(
float x,
float y)
const
1157 QQuick3DSceneRenderer *renderer = getRenderer();
1159 return QList<QQuick3DPickResult>();
1161 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1162 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1163 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1164 if (!rayResult.has_value())
1165 return QList<QQuick3DPickResult>();
1167 const auto resultList = renderer->syncPickAll(rayResult.value());
1168 QList<QQuick3DPickResult> processedResultList;
1169 processedResultList.reserve(resultList.size());
1170 for (
const auto &result : resultList)
1171 processedResultList.append(processPickResult(result));
1173 return processedResultList;
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction)
const
1191 QQuick3DSceneRenderer *renderer = getRenderer();
1193 return QQuick3DPickResult();
1195 const QSSGRenderRay ray(origin, direction);
1196 const auto resultList = renderer->syncPick(ray);
1197 return getNearestPickResult(resultList);
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216QList<QQuick3DPickResult> QQuick3DViewport::rayPickAll(
const QVector3D &origin,
const QVector3D &direction)
const
1218 QQuick3DSceneRenderer *renderer = getRenderer();
1220 return QList<QQuick3DPickResult>();
1222 const QSSGRenderRay ray(origin, direction);
1224 const auto resultList = renderer->syncPickAll(ray);
1225 QList<QQuick3DPickResult> processedResultList;
1226 processedResultList.reserve(resultList.size());
1227 for (
const auto &result : resultList) {
1228 auto processedResult = processPickResult(result);
1229 if (processedResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1230 processedResultList.append(processedResult);
1233 return processedResultList;
1237
1238
1239
1240
1241
1242
1243
1244QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction, QQuick3DModel *model)
const
1246 QQuick3DSceneRenderer *renderer = getRenderer();
1248 return QQuick3DPickResult();
1250 const QSSGRenderRay ray(origin, direction);
1252 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1253 const auto resultList = renderer->syncPickOne(ray, renderNode);
1254 return getNearestPickResult(resultList);
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267QQuick3DPickResult QQuick3DViewport::closestPointPick(
const QVector3D &origin,
float radius, QQuick3DModel *model)
const
1269 QQuick3DSceneRenderer *renderer = getRenderer();
1272 return QQuick3DPickResult();
1273 QSSGRenderNode *renderNode =
nullptr;
1275 renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1276 if (Q_UNLIKELY(!renderNode))
1277 return QQuick3DPickResult{};
1280 const auto pickResult = renderer->syncPickClosestPoint(origin, radius * radius, renderNode);
1281 if (!pickResult.has_value())
1282 return QQuick3DPickResult{};
1283 return processPickResult(pickResult.value());
1286void QQuick3DViewport::processPointerEventFromRay(
const QVector3D &origin,
const QVector3D &direction, QPointerEvent *event)
const
1288 internalPick(event, origin, direction);
1295class SyntheticTouchDevice :
public QPointingDevice
1298 SyntheticTouchDevice(QObject *parent =
nullptr)
1299 : QPointingDevice(QLatin1StringView(
"QtQuick3D Touch Synthesizer"),
1301 DeviceType::TouchScreen,
1302 PointerType::Finger,
1303 Capability::Position,
1305 QString(), QPointingDeviceUniqueId(),
1313
1314
1315
1316
1317
1318
1319
1320
1321
1323void QQuick3DViewport::setTouchpoint(QQuickItem *target,
const QPointF &position,
int pointId,
bool pressed)
1325 if (pointId >= m_touchState.size())
1326 m_touchState.resize(pointId + 1);
1327 auto prevState = m_touchState[pointId];
1329 const bool sameTarget = prevState.target == target;
1330 const bool wasPressed = prevState.isPressed;
1332 const bool isPress = pressed && (!sameTarget || !wasPressed);
1333 const bool isRelease = !pressed && wasPressed && sameTarget;
1338 if (!sameTarget && wasPressed)
1339 qWarning(
"QQuick3DViewport::setTouchpoint missing release event");
1341 if (!pressed && !wasPressed) {
1346 m_touchState[pointId] = { target, position, pressed };
1348 if (!m_syntheticTouchDevice)
1349 m_syntheticTouchDevice =
new SyntheticTouchDevice(
this);
1351 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(m_syntheticTouchDevice);
1353 auto makePoint = [devPriv](
int id, QEventPoint::State pointState, QPointF pos, quint64 timestamp) -> QEventPoint {
1354 auto epd = devPriv->pointById(id);
1355 auto &ep = epd->eventPoint;
1356 if (pointState != QEventPoint::State::Stationary)
1357 ep.setAccepted(
false);
1359 auto res = QMutableEventPoint::withTimeStamp(timestamp, id, pointState, pos, pos, pos);
1360 QMutableEventPoint::update(res, ep);
1362 if (pointState == QEventPoint::State::Pressed)
1363 QMutableEventPoint::setGlobalPressPosition(res, pos);
1364 else if (ep.state() != QEventPoint::State::Unknown)
1365 QMutableEventPoint::setGlobalPressPosition(res, ep.globalPressPosition());
1370 auto sendTouchEvent = [&](QQuickItem *t,
const QPointF &position,
int pointId, QEventPoint::State pointState, quint64 timestamp) ->
void {
1371 QList<QEventPoint> points;
1372 bool otherPoint =
false;
1373 for (
int i = 0; i < m_touchState.size(); ++i) {
1374 const auto &ts = m_touchState[i];
1378 auto newPoint = makePoint(i, pointState, position, timestamp);
1380 }
else if (ts.isPressed) {
1382 points << makePoint(i, QEventPoint::Stationary, ts.position, timestamp);
1387 if (pointState == QEventPoint::Pressed && !otherPoint)
1388 type = QEvent::Type::TouchBegin;
1389 else if (pointState == QEventPoint::Released && !otherPoint)
1390 type = QEvent::Type::TouchEnd;
1392 type = QEvent::Type::TouchUpdate;
1394 QTouchEvent ev(type, m_syntheticTouchDevice, {}, points);
1395 ev.setTimestamp(timestamp);
1399 auto da = QQuickItemPrivate::get(t)->deliveryAgent();
1400 bool handled = da->event(&ev);
1405 if (ev.isEndEvent()) {
1406 for (
auto &point : ev.points()) {
1407 if (point.state() == QEventPoint::State::Released) {
1408 ev.setExclusiveGrabber(point,
nullptr);
1409 ev.clearPassiveGrabbers(point);
1415 auto timestamp = QDateTime::currentMSecsSinceEpoch();
1418 if (prevState.target && !sameTarget)
1419 sendTouchEvent(prevState.target, prevState.position, pointId, QEventPoint::Released, timestamp);
1422 QEventPoint::State newState = isPress ? QEventPoint::Pressed : isRelease ? QEventPoint::Released : QEventPoint::Updated;
1423 sendTouchEvent(target, position, pointId, newState, timestamp);
1426QQuick3DLightmapBaker *QQuick3DViewport::maybeLightmapBaker()
1428 return m_lightmapBaker;
1431QQuick3DLightmapBaker *QQuick3DViewport::lightmapBaker()
1433 if (!m_lightmapBaker)
1434 m_lightmapBaker=
new QQuick3DLightmapBaker(
this);
1436 return m_lightmapBaker;
1440
1441
1442void QQuick3DViewport::bakeLightmap()
1444 QQuick3DSceneRenderer *renderer = getRenderer();
1445 if (!renderer || !renderer->m_layer->renderData)
1448 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1450 if (!currentlyBaking)
1451 lightmapBaker()->bake();
1455
1456
1457void QQuick3DViewport::denoiseLightmap()
1459 QQuick3DSceneRenderer *renderer = getRenderer();
1460 if (!renderer || !renderer->m_layer->renderData)
1463 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1465 if (!currentlyBaking)
1466 lightmapBaker()->denoise();
1470void QQuick3DViewport::setGlobalPickingEnabled(
bool isEnabled)
1472 QQuick3DSceneRenderer *renderer = getRenderer();
1476 renderer->setGlobalPickingEnabled(isEnabled);
1479void QQuick3DViewport::invalidateSceneGraph()
1484QQuick3DSceneRenderer *QQuick3DViewport::getRenderer()
const
1486 QQuick3DSceneRenderer *renderer =
nullptr;
1488 renderer = m_node->renderer;
1489 }
else if (m_renderNode) {
1490 renderer = m_renderNode->renderer;
1491 }
else if (m_directRenderer) {
1492 renderer = m_directRenderer->renderer();
1497void QQuick3DViewport::updateDynamicTextures()
1502 const auto &sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
1503 for (
auto *texture : std::as_const(sceneManager->qsgDynamicTextures))
1504 texture->updateTexture();
1506 QQuick3DNode *scene = m_importScene;
1508 const auto &importSm = QQuick3DObjectPrivate::get(scene)->sceneManager;
1509 if (importSm != sceneManager) {
1510 for (
auto *texture : std::as_const(importSm->qsgDynamicTextures))
1511 texture->updateTexture();
1515 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
1516 scene = rn ? rn->view3D()->importScene() :
nullptr;
1520QSGNode *QQuick3DViewport::setupOffscreenRenderer(QSGNode *node)
1522 SGFramebufferObjectNode *n =
static_cast<SGFramebufferObjectNode *>(node);
1526 m_node =
new SGFramebufferObjectNode;
1531 n->window = window();
1532 n->renderer = createRenderer();
1535 n->renderer->fboNode = n;
1537 connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
1540 const qreal dpr = window()->effectiveDevicePixelRatio();
1541 const QSize minFboSize = QQuickItemPrivate::get(
this)->sceneGraphContext()->minimumFBOSize();
1542 QSize desiredFboSize = QSize(m_explicitTextureWidth, m_explicitTextureHeight);
1543 if (desiredFboSize.isEmpty()) {
1544 desiredFboSize = QSize(width(), height()) * dpr;
1545 n->devicePixelRatio = dpr;
1547 m_widthMultiplier = 1.0f;
1548 m_heightMultiplier = 1.0f;
1550 QSize itemPixelSize = QSize(width(), height()) * dpr;
1552 m_widthMultiplier = desiredFboSize.width() /
float(itemPixelSize.width());
1553 m_heightMultiplier = desiredFboSize.height() /
float(itemPixelSize.height());
1554 n->devicePixelRatio = 1.0;
1556 desiredFboSize.setWidth(qMax(minFboSize.width(), desiredFboSize.width()));
1557 desiredFboSize.setHeight(qMax(minFboSize.height(), desiredFboSize.height()));
1559 if (desiredFboSize != m_effectiveTextureSize) {
1560 m_effectiveTextureSize = desiredFboSize;
1561 emit effectiveTextureSizeChanged();
1564 n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1565 n->setRect(0, 0, width(), height());
1566 if (checkIsVisible() && isComponentComplete()) {
1567 n->renderer->synchronize(
this, desiredFboSize, n->devicePixelRatio);
1568 if (n->renderer->m_textureNeedsFlip)
1569 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
1570 updateDynamicTextures();
1571 n->scheduleRender();
1577QSGNode *QQuick3DViewport::setupInlineRenderer(QSGNode *node)
1579 QQuick3DSGRenderNode *n =
static_cast<QQuick3DSGRenderNode *>(node);
1582 m_renderNode =
new QQuick3DSGRenderNode;
1587 n->window = window();
1588 n->renderer = createRenderer();
1593 if (!m_effectiveTextureSize.isEmpty()) {
1594 m_effectiveTextureSize = QSize();
1595 emit effectiveTextureSizeChanged();
1598 const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
1603 if (checkIsVisible() && isComponentComplete()) {
1604 n->renderer->synchronize(
this, targetSize, window()->effectiveDevicePixelRatio());
1605 updateDynamicTextures();
1606 n->markDirty(QSGNode::DirtyMaterial);
1613void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
1615 auto renderMode = (mode == Underlay) ? QQuick3DSGDirectRenderer::Underlay
1616 : QQuick3DSGDirectRenderer::Overlay;
1617 if (!m_directRenderer) {
1618 QQuick3DSceneRenderer *sceneRenderer = createRenderer();
1621 m_directRenderer =
new QQuick3DSGDirectRenderer(sceneRenderer, window(), renderMode);
1622 connect(window(), &QQuickWindow::sceneGraphInvalidated,
this, &QQuick3DViewport::cleanupDirectRenderer, Qt::DirectConnection);
1625 if (!m_effectiveTextureSize.isEmpty()) {
1626 m_effectiveTextureSize = QSize();
1627 emit effectiveTextureSizeChanged();
1630 const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
1631 m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
1632 m_directRenderer->setVisibility(isVisible());
1634 m_directRenderer->preSynchronize();
1635 m_directRenderer->renderer()->synchronize(
this, targetSize.toSize(), window()->effectiveDevicePixelRatio());
1636 updateDynamicTextures();
1637 m_directRenderer->requestRender();
1643bool QQuick3DViewport::checkIsVisible()
const
1645 auto childPrivate = QQuickItemPrivate::get(
this);
1646 return (childPrivate->explicitVisible ||
1647 (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
1652
1653
1654
1655
1656
1657
1658
1659
1660void QQuick3DViewport::processPickedObject(
const QSSGRenderPickResult &pickResult,
1662 QPointerEvent *event,
1663 QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1665 QQuickItem *subsceneRootItem =
nullptr;
1666 QPointF subscenePosition;
1667 const auto backendObject = pickResult.m_hitObject;
1668 const auto frontendObject = findFrontendNode(backendObject);
1669 if (!frontendObject)
1675 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1676 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1679 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1681 subsceneRootItem = item2D->contentItem();
1682 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1686 subscenePosition = pickResult.m_localUVCoords.toPointF();
1690 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1692 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1694 int materialSubset = pickResult.m_subset;
1695 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1697 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1698 materialSubset = backendModel->materials.size() - 1;
1699 if (materialSubset < 0)
1701 const auto backendMaterial = backendModel->materials.at(materialSubset);
1702 const auto frontendMaterial =
static_cast<QQuick3DMaterial*>(findFrontendNode(backendMaterial));
1703 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1705 if (subsceneRootItem) {
1707 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1708 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1713 if (subsceneRootItem) {
1714 SubsceneInfo &subscene = visitedSubscenes[subsceneRootItem];
1715 subscene.obj = frontendObject;
1716 if (subscene.eventPointScenePositions.size() != event->pointCount()) {
1718 constexpr QPointF inf(-qt_inf(), -qt_inf());
1719 subscene.eventPointScenePositions.resize(event->pointCount(), inf);
1721 subscene.eventPointScenePositions[pointIndex] = subscenePosition;
1726
1727
1728
1729
1730
1731
1732
1733
1735QQuickItem *QQuick3DViewport::getSubSceneRootItem(QQuick3DMaterial *material)
const
1740 QQuickItem *subsceneRootItem =
nullptr;
1741 const auto frontendMaterialPrivate = QQuick3DObjectPrivate::get(material);
1743 if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::DefaultMaterial) {
1745 const auto defaultMaterial = qobject_cast<QQuick3DDefaultMaterial *>(material);
1746 if (defaultMaterial) {
1748 if (defaultMaterial->diffuseMap() && defaultMaterial->diffuseMap()->sourceItem())
1749 subsceneRootItem = defaultMaterial->diffuseMap()->sourceItem();
1752 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::PrincipledMaterial) {
1754 const auto principledMaterial = qobject_cast<QQuick3DPrincipledMaterial *>(material);
1755 if (principledMaterial) {
1757 if (principledMaterial->baseColorMap() && principledMaterial->baseColorMap()->sourceItem())
1758 subsceneRootItem = principledMaterial->baseColorMap()->sourceItem();
1760 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::SpecularGlossyMaterial) {
1762 const auto specularGlossyMaterial = qobject_cast<QQuick3DSpecularGlossyMaterial *>(material);
1763 if (specularGlossyMaterial) {
1765 if (specularGlossyMaterial->albedoMap() && specularGlossyMaterial->albedoMap()->sourceItem())
1766 subsceneRootItem = specularGlossyMaterial->albedoMap()->sourceItem();
1768 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
1770 const auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material);
1771 if (customMaterial) {
1773 const auto &texturesInputs = customMaterial->m_dynamicTextureMaps;
1774 for (
const auto &textureInput : texturesInputs) {
1775 if (
auto texture = textureInput->texture()) {
1776 if (texture->sourceItem()) {
1777 subsceneRootItem = texture->sourceItem();
1784 return subsceneRootItem;
1789
1790
1791QQuick3DPickResult QQuick3DViewport::getNearestPickResult(
const QVarLengthArray<QSSGRenderPickResult, 20> &pickResults)
const
1793 for (
const auto &result : pickResults) {
1794 auto pickResult = processPickResult(result);
1795 if (pickResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1799 return QQuick3DPickResult();
1803
1804
1805
1806
1807
1808bool QQuick3DViewport::forwardEventToSubscenes(QPointerEvent *event,
1810 QQuick3DSceneRenderer *renderer,
1811 const QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1818 QVarLengthArray<QPointF, 16> originalScenePositions;
1819 originalScenePositions.resize(event->pointCount());
1820 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1821 originalScenePositions[pointIndex] = event->point(pointIndex).scenePosition();
1822 for (
auto subscene : visitedSubscenes) {
1823 QQuickItem *subsceneRoot = subscene.first;
1824 auto &subsceneInfo = subscene.second;
1825 Q_ASSERT(subsceneInfo.eventPointScenePositions.size() == event->pointCount());
1826 auto da = QQuickItemPrivate::get(subsceneRoot)->deliveryAgent();
1827 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1828 const auto &pt = subsceneInfo.eventPointScenePositions.at(pointIndex);
1833 QEventPoint &ep = event->point(pointIndex);
1834 QMutableEventPoint::setPosition(ep, pt);
1835 QMutableEventPoint::setScenePosition(ep, pt);
1838 if (event->isBeginEvent())
1839 da->setSceneTransform(
nullptr);
1840 if (da->event(event)) {
1842 if (QQuickDeliveryAgentPrivate::anyPointGrabbed(event) && !useRayPicking) {
1847 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(subsceneInfo.obj);
1848 const bool item2Dcase = (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D);
1849 ViewportTransformHelper *transform =
new ViewportTransformHelper;
1850 transform->viewport =
const_cast<QQuick3DViewport *>(
this);
1851 transform->renderer = renderer;
1852 transform->sceneParentNode =
static_cast<QSSGRenderNode*>(frontendObjectPrivate->spatialNode);
1853 transform->targetItem = subsceneRoot;
1854 transform->scaleX = window()->effectiveDevicePixelRatio() * m_widthMultiplier;
1855 transform->scaleY = window()->effectiveDevicePixelRatio() * m_heightMultiplier;
1856 transform->uvCoordsArePixels = item2Dcase;
1857 transform->setOnDeliveryAgent(da);
1858 qCDebug(lcPick) << event->type() <<
"created ViewportTransformHelper on" << da;
1860 }
else if (event->type() != QEvent::HoverMove) {
1861 qCDebug(lcPick) << subsceneRoot <<
"didn't want" << event;
1863 event->setAccepted(
false);
1865 if (visitedSubscenes.isEmpty()) {
1866 event->setAccepted(
false);
1868 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1869 QMutableEventPoint::setScenePosition(event->point(pointIndex), originalScenePositions.at(pointIndex));
1875 if (event->isEndEvent() && useRayPicking) {
1876 if (event->isSinglePointEvent()) {
1877 if (
static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
1878 auto &firstPt = event->point(0);
1879 event->setExclusiveGrabber(firstPt,
nullptr);
1880 event->clearPassiveGrabbers(firstPt);
1883 for (
auto &point : event->points()) {
1884 if (point.state() == QEventPoint::State::Released) {
1885 event->setExclusiveGrabber(point,
nullptr);
1886 event->clearPassiveGrabbers(point);
1896bool QQuick3DViewport::internalPick(QPointerEvent *event,
const QVector3D &origin,
const QVector3D &direction)
const
1898 QQuick3DSceneRenderer *renderer = getRenderer();
1899 if (!renderer || !event)
1902 QFlatMap<QQuickItem*, SubsceneInfo> visitedSubscenes;
1903 const bool useRayPicking = !direction.isNull();
1905 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1906 auto &eventPoint = event->point(pointIndex);
1907 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
1908 if (Q_UNLIKELY(useRayPicking))
1909 pickResults = getPickResults(renderer, origin, direction);
1911 pickResults = getPickResults(renderer, eventPoint);
1913 if (!pickResults.isEmpty())
1914 for (
const auto &pickResult : pickResults)
1915 processPickedObject(pickResult, pointIndex, event, visitedSubscenes);
1917 eventPoint.setAccepted(
false);
1920 return forwardEventToSubscenes(event, useRayPicking, renderer, visitedSubscenes);
1923bool QQuick3DViewport::singlePointPick(QSinglePointEvent *event,
const QVector3D &origin,
const QVector3D &direction)
1925 QQuick3DSceneRenderer *renderer = getRenderer();
1926 if (!renderer || !event)
1929 QSSGRenderRay ray(origin, direction);
1931 Q_ASSERT(event->pointCount() == 1);
1932 QPointF originalPosition = event->point(0).scenePosition();
1934 auto pickResults = renderer->syncPickAll(ray);
1936 bool delivered =
false;
1938 constexpr float jitterLimit = 2.5;
1939 bool withinJitterLimit =
false;
1941 for (
const auto &pickResult : pickResults) {
1942 auto [item, position] = getItemAndPosition(pickResult);
1945 if (item == m_prevMouseItem && (position - m_prevMousePos).manhattanLength() < jitterLimit && !event->button()) {
1946 withinJitterLimit =
true;
1949 auto da = QQuickItemPrivate::get(item)->deliveryAgent();
1950 QEventPoint &ep = event->point(0);
1951 QMutableEventPoint::setPosition(ep, position);
1952 QMutableEventPoint::setScenePosition(ep, position);
1953 if (da->event(event)) {
1955 if (event->type() == QEvent::MouseButtonPress) {
1956 m_prevMouseItem = item;
1957 m_prevMousePos = position;
1958 withinJitterLimit =
true;
1964 QMutableEventPoint::setScenePosition(event->point(0), originalPosition);
1965 if (!withinJitterLimit)
1966 m_prevMouseItem =
nullptr;
1971 if (event->isEndEvent()) {
1972 if (event->buttons() == Qt::NoButton) {
1973 auto &firstPt = event->point(0);
1974 event->setExclusiveGrabber(firstPt,
nullptr);
1975 event->clearPassiveGrabbers(firstPt);
1982QPair<QQuickItem *, QPointF> QQuick3DViewport::getItemAndPosition(
const QSSGRenderPickResult &pickResult)
const
1984 QQuickItem *subsceneRootItem =
nullptr;
1985 QPointF subscenePosition;
1986 const auto backendObject = pickResult.m_hitObject;
1987 const auto frontendObject = findFrontendNode(backendObject);
1988 if (!frontendObject)
1990 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1991 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1994 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1996 subsceneRootItem = item2D->contentItem();
1997 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
2001 subscenePosition = pickResult.m_localUVCoords.toPointF();
2005 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
2007 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
2009 int materialSubset = pickResult.m_subset;
2010 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
2012 if (backendModel->materials.size() < (pickResult.m_subset + 1))
2013 materialSubset = backendModel->materials.size() - 1;
2014 if (materialSubset < 0)
2016 const auto backendMaterial = backendModel->materials.at(materialSubset);
2017 const auto frontendMaterial =
static_cast<QQuick3DMaterial *>(findFrontendNode(backendMaterial));
2018 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
2020 if (subsceneRootItem) {
2022 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
2023 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
2026 return {subsceneRootItem, subscenePosition};
2029QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
2030 const QVector3D &origin,
2031 const QVector3D &direction)
const
2033 const QSSGRenderRay ray(origin, direction);
2034 return renderer->syncPickAll(ray);
2037QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
const QEventPoint &eventPoint)
const
2039 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
2040 QPointF realPosition = eventPoint.position() * window()->effectiveDevicePixelRatio();
2042 realPosition.rx() *= m_widthMultiplier;
2043 realPosition.ry() *= m_heightMultiplier;
2044 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(realPosition);
2045 if (rayResult.has_value())
2046 pickResults = renderer->syncPickAll(rayResult.value());
2051
2052
2053
2054
2055
2056QQuick3DObject *QQuick3DViewport::findFrontendNode(
const QSSGRenderGraphObject *backendObject)
const
2061 const auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2062 QQuick3DObject *frontendObject = sceneManager->lookUpNode(backendObject);
2063 if (!frontendObject && m_importScene) {
2064 const auto importSceneManager = QQuick3DObjectPrivate::get(m_importScene)->sceneManager;
2065 frontendObject = importSceneManager->lookUpNode(backendObject);
2067 return frontendObject;
2070QQuick3DPickResult QQuick3DViewport::processPickResult(
const QSSGRenderPickResult &pickResult)
const
2072 if (!pickResult.m_hitObject)
2073 return QQuick3DPickResult();
2075 QQuick3DObject *frontendObject = findFrontendNode(pickResult.m_hitObject);
2077 QQuick3DModel *model = qobject_cast<QQuick3DModel *>(frontendObject);
2079 auto itemAndPosition = getItemAndPosition(pickResult);
2080 return QQuick3DPickResult(model,
2081 ::sqrtf(pickResult.m_distanceSq),
2082 pickResult.m_localUVCoords,
2083 pickResult.m_scenePosition,
2084 pickResult.m_localPosition,
2085 pickResult.m_faceNormal,
2086 pickResult.m_sceneNormal,
2087 pickResult.m_instanceIndex,
2088 itemAndPosition.first);
2091 QQuick3DItem2D *frontend2DItem = qobject_cast<QQuick3DItem2D *>(frontendObject);
2092 if (frontend2DItem && frontend2DItem->contentItem()) {
2094 const QPointF subscenePosition = pickResult.m_localUVCoords.toPointF();
2095 const auto child = frontend2DItem->contentItem()->childAt(subscenePosition.x(), subscenePosition.y());
2097 return QQuick3DPickResult(child,
2098 ::sqrtf(pickResult.m_distanceSq),
2099 QVector2D(frontend2DItem->contentItem()->mapToItem(child, subscenePosition)),
2100 pickResult.m_scenePosition,
2101 pickResult.m_localPosition,
2102 pickResult.m_faceNormal);
2106 return QQuick3DPickResult();
2111QQuick3DSceneManager *QQuick3DViewport::findChildSceneManager(QQuick3DObject *inObject, QQuick3DSceneManager *manager)
2116 auto children = QQuick3DObjectPrivate::get(inObject)->childItems;
2117 for (
auto child : children) {
2118 if (
auto m = QQuick3DObjectPrivate::get(child)->sceneManager) {
2122 manager = findChildSceneManager(child, manager);
2127void QQuick3DViewport::updateInputProcessing()
2130 setAcceptTouchEvents(m_enableInputProcessing);
2131 setAcceptHoverEvents(m_enableInputProcessing);
2132 setAcceptedMouseButtons(m_enableInputProcessing ? Qt::AllButtons : Qt::NoButton);
2135void QQuick3DViewport::onReleaseCachedResources()
2137 if (
auto renderer = getRenderer())
2138 renderer->releaseCachedResources();
2142
2143
2144
2145
2146
2147
2148QQmlListProperty<QQuick3DObject> QQuick3DViewport::extensions()
2150 return QQmlListProperty<QQuick3DObject>{
this,
2151 &m_extensionListDirty,
2152 &QQuick3DExtensionListHelper::extensionAppend,
2153 &QQuick3DExtensionListHelper::extensionCount,
2154 &QQuick3DExtensionListHelper::extensionAt,
2155 &QQuick3DExtensionListHelper::extensionClear,
2156 &QQuick3DExtensionListHelper::extensionReplace,
2157 &QQuick3DExtensionListHelper::extensionRemoveLast};
2161
2162
2163void QQuick3DViewport::rebuildExtensionList()
2165 m_extensionListDirty =
true;
2170
2171
2172
2173
2174
2175QQuick3DViewport::QQuick3DViewport(PrivateInstanceType type, QQuickItem *parent)
2176 : QQuick3DViewport(parent)
2178 m_isXrViewInstance = type == PrivateInstanceType::XrViewInstance;
2181void QQuick3DViewport::updateCameraForLayer(
const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode)
2183 layerNode.explicitCameras.clear();
2184 if (!view3D.m_multiViewCameras.isEmpty()) {
2185 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
2186 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
2187 }
else if (view3D.camera()) {
2188 if (QSSGRenderCamera *camera =
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode))
2189 layerNode.explicitCameras.append(camera);
2194 for (QSSGRenderCamera *camera : std::as_const(layerNode.explicitCameras)) {
2195 if (!camera->parent)
2196 layerNode.addChild(*camera);
2200void QQuick3DViewport::updateSceneManagerForImportScene()
2202 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2203 if (!privateObject->sceneManager) {
2205 QQuick3DSceneManager *manager = findChildSceneManager(m_importScene);
2208 manager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2210 manager->setWindow(window());
2211 privateObject->refSceneManager(*manager);
2216 if (!privateObject->sceneManager)
2220 connect(privateObject->sceneManager, &QQuick3DSceneManager::needsUpdate,
2221 this, &QQuickItem::update, Qt::UniqueConnection);
2222 connect(privateObject->sceneManager, &QObject::destroyed,
2223 this, [&](QObject *) {
2224 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2225 privateObject->sceneManager =
nullptr;
2226 updateSceneManagerForImportScene();
2227 }, Qt::DirectConnection);
2229 QQuick3DNode *scene = m_importScene;
2231 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
2232 scene = rn ? rn->view3D()->importScene() :
nullptr;
2235 connect(QQuick3DObjectPrivate::get(scene)->sceneManager,
2236 &QQuick3DSceneManager::needsUpdate,
2237 this, &QQuickItem::update, Qt::UniqueConnection);
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)