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
363QQuick3DCamera *QQuick3DViewport::camera()
const
369
370
371
372
373
374
375
376
377QQuick3DSceneEnvironment *QQuick3DViewport::environment()
const
379 if (!m_environment) {
380 if (!m_builtInEnvironment) {
381 m_builtInEnvironment =
new QQuick3DSceneEnvironment;
385 if (QThread::currentThread() != m_sceneRoot->thread())
386 m_builtInEnvironment->moveToThread(m_sceneRoot->thread());
387 m_builtInEnvironment->setParentItem(m_sceneRoot);
390 return m_builtInEnvironment;
393 return m_environment;
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416QQuick3DNode *QQuick3DViewport::scene()
const
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440QQuick3DNode *QQuick3DViewport::importScene()
const
442 return m_importScene;
446
447
448
449
450
451
452
453
454
455
456
457
458
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
488QQuick3DViewport::RenderMode QQuick3DViewport::renderMode()
const
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514#if QT_CONFIG(quick_shadereffect)
515QQuickShaderEffectSource::Format QQuick3DViewport::renderFormat()
const
517 return m_renderFormat;
522
523
524
525
526
527
528
529
530QQuick3DRenderStats *QQuick3DViewport::renderStats()
const
532 return m_renderStats;
535QQuick3DSceneRenderer *QQuick3DViewport::createRenderer()
const
537 QQuick3DSceneRenderer *renderer =
nullptr;
539 if (QQuickWindow *qw = window()) {
540 auto wa = QQuick3DSceneManager::getOrSetWindowAttachment(*qw);
541 auto rci = wa->rci();
543 QSGRendererInterface *rif = qw->rendererInterface();
544 if (QSSG_GUARD(QSGRendererInterface::isApiRhiBased(rif->graphicsApi()))) {
545 QRhi *rhi =
static_cast<QRhi *>(rif->getResource(qw, QSGRendererInterface::RhiResource));
546 QSSG_CHECK_X(rhi !=
nullptr,
"No QRhi from QQuickWindow, this cannot happen");
556 rci = std::make_shared<QSSGRenderContextInterface>(rhi);
560 connect(wa, &QQuick3DWindowAttachment::releaseCachedResources,
this,
561 &QQuick3DViewport::onReleaseCachedResources, Qt::DirectConnection);
564 qWarning(
"The Qt Quick scene is using a rendering method that is not based on QRhi and a 3D graphics API. "
565 "Qt Quick 3D is not functional in such an environment. The View3D item is not going to display anything.");
570 renderer =
new QQuick3DSceneRenderer(rci);
571 Q_QUICK3D_PROFILE_ASSIGN_ID(
this, renderer);
578bool QQuick3DViewport::isTextureProvider()
const
581 if (m_renderMode == QQuick3DViewport::Offscreen)
587QSGTextureProvider *QQuick3DViewport::textureProvider()
const
592 if (QQuickItem::isTextureProvider())
593 return QQuickItem::textureProvider();
596 if (m_renderMode != QQuick3DViewport::Offscreen)
599 QQuickWindow *w = window();
601 qWarning(
"QSSGView3D::textureProvider: can only be queried on the rendering thread of an exposed window");
606 m_node =
new SGFramebufferObjectNode;
619void QQuick3DViewport::releaseResources()
621 if (m_directRenderer) {
622 window()->scheduleRenderJob(
new CleanupJob(m_directRenderer), QQuickWindow::BeforeSynchronizingStage);
623 m_directRenderer =
nullptr;
629void QQuick3DViewport::cleanupDirectRenderer()
631 delete m_directRenderer;
632 m_directRenderer =
nullptr;
635void QQuick3DViewport::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
637 QQuickItem::geometryChange(newGeometry, oldGeometry);
639 if (newGeometry.size() != oldGeometry.size())
643QSGNode *QQuick3DViewport::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
646 if (m_renderModeDirty) {
651 m_renderNode =
nullptr;
653 if (m_directRenderer) {
654 delete m_directRenderer;
655 m_directRenderer =
nullptr;
659 m_renderModeDirty =
false;
661 switch (m_renderMode) {
666 setupDirectRenderer(m_renderMode);
670 node = setupOffscreenRenderer(node);
674 node = setupInlineRenderer(node);
678 if (!isforceInputHandlingSet()) {
680 const auto inputHandlingEnabled =
681 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->inputHandlingEnabled;
682 const auto enable = inputHandlingEnabled > 0;
683 if (m_enableInputProcessing != enable) {
684 m_enableInputProcessing = enable;
685 QMetaObject::invokeMethod(
this,
"updateInputProcessing", Qt::QueuedConnection);
692void QQuick3DViewport::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
694 if (change == ItemSceneChange) {
698 QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager->setWindow(value.window);
700 QQuick3DObjectPrivate::get(m_importScene)->sceneManager->setWindow(value.window);
701 m_renderStats->setWindow(value.window);
703 }
else if (change == ItemVisibleHasChanged && isVisible()) {
708bool QQuick3DViewport::event(QEvent *event)
710 if (m_enableInputProcessing && event->isPointerEvent())
711 return internalPick(
static_cast<QPointerEvent *>(event));
713 return QQuickItem::event(event);
716void QQuick3DViewport::componentComplete()
718 QQuickItem::componentComplete();
719 Q_QUICK3D_PROFILE_REGISTER(
this);
722void QQuick3DViewport::setCamera(QQuick3DCamera *camera)
724 if (m_camera == camera)
727 if (camera && !camera->parentItem())
728 camera->setParentItem(m_sceneRoot);
730 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
732 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setCamera, camera, m_camera);
735 emit cameraChanged();
739void QQuick3DViewport::setMultiViewCameras(QQuick3DCamera **firstCamera,
int count)
741 m_multiViewCameras.clear();
742 bool sendChangeSignal =
false;
743 for (
int i = 0; i < count; ++i) {
744 QQuick3DCamera *camera = *(firstCamera + i);
746 if (!camera->parentItem())
747 camera->setParentItem(m_sceneRoot);
748 camera->updateGlobalVariables(QRect(0, 0, width(), height()));
751 if (m_camera != camera) {
753 sendChangeSignal =
true;
757 m_multiViewCameras.append(camera);
762 if (sendChangeSignal)
763 emit cameraChanged();
768void QQuick3DViewport::setEnvironment(QQuick3DSceneEnvironment *environment)
770 if (m_environment == environment)
773 m_environment = environment;
774 if (m_environment && !m_environment->parentItem())
775 m_environment->setParentItem(m_sceneRoot);
777 QQuick3DObjectPrivate::attachWatcherPriv(m_sceneRoot,
this, &QQuick3DViewport::setEnvironment, environment, m_environment);
779 emit environmentChanged();
783void QQuick3DViewport::setImportScene(QQuick3DNode *inScene)
793 QQuick3DNode *scene = inScene;
795 if (m_sceneRoot == scene) {
796 qmlWarning(
this) <<
"Cannot allow self-import or cross-import!";
800 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
801 scene = rn ? rn->view3D()->importScene() :
nullptr;
804 m_importScene = inScene;
806 updateSceneManagerForImportScene();
808 emit importSceneChanged();
812void QQuick3DViewport::setRenderMode(QQuick3DViewport::RenderMode renderMode)
814 if (m_renderMode == renderMode)
817 m_renderMode = renderMode;
818 m_renderModeDirty =
true;
819 emit renderModeChanged();
823#if QT_CONFIG(quick_shadereffect)
824void QQuick3DViewport::setRenderFormat(QQuickShaderEffectSource::Format format)
826 if (m_renderFormat == format)
829 m_renderFormat = format;
830 m_renderModeDirty =
true;
831 emit renderFormatChanged();
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855int QQuick3DViewport::explicitTextureWidth()
const
857 return m_explicitTextureWidth;
860void QQuick3DViewport::setExplicitTextureWidth(
int width)
862 if (m_explicitTextureWidth == width)
865 m_explicitTextureWidth = width;
866 emit explicitTextureWidthChanged();
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889int QQuick3DViewport::explicitTextureHeight()
const
891 return m_explicitTextureHeight;
894void QQuick3DViewport::setExplicitTextureHeight(
int height)
896 if (m_explicitTextureHeight == height)
899 m_explicitTextureHeight = height;
900 emit explicitTextureHeightChanged();
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919QSize QQuick3DViewport::effectiveTextureSize()
const
921 return m_effectiveTextureSize;
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941QVector3D QQuick3DViewport::mapFrom3DScene(
const QVector3D &scenePos)
const
944 qmlWarning(
this) <<
"Cannot resolve view position without a camera assigned!";
945 return QVector3D(0, 0, 0);
948 qreal _width = width();
949 qreal _height = height();
950 if (_width == 0 || _height == 0)
951 return QVector3D(0, 0, 0);
953 const QVector3D normalizedPos = m_camera->mapToViewport(scenePos, _width, _height);
954 return normalizedPos * QVector3D(
float(_width),
float(_height), 1);
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974QVector3D QQuick3DViewport::mapTo3DScene(
const QVector3D &viewPos)
const
977 qmlWarning(
this) <<
"Cannot resolve scene position without a camera assigned!";
978 return QVector3D(0, 0, 0);
981 qreal _width = width();
982 qreal _height = height();
983 if (_width == 0 || _height == 0)
984 return QVector3D(0, 0, 0);
986 const QVector3D normalizedPos = viewPos / QVector3D(
float(_width),
float(_height), 1);
987 return m_camera->mapFromViewport(normalizedPos, _width, _height);
991
992
993
994
995
996
997
998QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y)
const
1000 QQuick3DSceneRenderer *renderer = getRenderer();
1002 return QQuick3DPickResult();
1004 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1005 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1006 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1007 if (!rayResult.has_value())
1008 return QQuick3DPickResult();
1010 const auto resultList = renderer->syncPick(rayResult.value());
1011 return getNearestPickResult(resultList);
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024QQuick3DPickResult QQuick3DViewport::pick(
float x,
float y, QQuick3DModel *model)
const
1026 QQuick3DSceneRenderer *renderer = getRenderer();
1028 return QQuick3DPickResult();
1030 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1031 qreal(y) * window()->effectiveDevicePixelRatio());
1032 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1034 if (!rayResult.has_value())
1035 return QQuick3DPickResult();
1037 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1038 const auto resultList = renderer->syncPickOne(rayResult.value(), renderNode);
1039 return getNearestPickResult(resultList);
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057QList<QQuick3DPickResult> QQuick3DViewport::pickSubset(
float x,
float y,
const QJSValue &models)
const
1059 QQuick3DSceneRenderer *renderer = getRenderer();
1063 QVarLengthArray<QSSGRenderNode*> renderNodes;
1065 if (models.isArray()) {
1066 const auto length = models.property(QStringLiteral(
"length")).toInt();
1070 for (
int i = 0; i < length; ++i) {
1071 const auto isQObject = models.property(i).isQObject();
1073 qmlWarning(
this) <<
"Type provided for picking is not a QObject. Needs to be of type QQuick3DModel.";
1076 const auto obj = models.property(i).toQObject();
1077 const auto model = qobject_cast<QQuick3DModel *>(obj);
1079 qmlWarning(
this) <<
"Type " << obj->metaObject()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1082 const auto priv = QQuick3DObjectPrivate::get(model);
1083 if (priv && priv->spatialNode) {
1084 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1089 const auto subsetVariant = models.toVariant();
1090 if (!subsetVariant.isValid() || !subsetVariant.canConvert<QQmlListReference>())
1093 const auto list = subsetVariant.value<QQmlListReference>();
1096 if (list.listElementType()->className() != QQuick3DModel::staticMetaObject.className()) {
1097 qmlWarning(
this) <<
"Type " << list.listElementType()->className() <<
" is not supported for picking. Needs to be of type QQuick3DModel.";
1100 for (
int i = 0; i < list.count(); ++i) {
1101 auto model =
static_cast<QQuick3DModel *>(list.at(i));
1104 auto priv = QQuick3DObjectPrivate::get(model);
1105 if (priv && priv->spatialNode) {
1106 renderNodes.push_back(
static_cast<QSSGRenderNode*>(priv->spatialNode));
1111 if (renderNodes.empty())
1114 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio(),
1115 qreal(y) * window()->effectiveDevicePixelRatio());
1116 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1117 if (!rayResult.has_value())
1120 const auto resultList = renderer->syncPickSubset(rayResult.value(), renderNodes);
1122 QList<QQuick3DPickResult> processedResultList;
1123 processedResultList.reserve(resultList.size());
1124 for (
const auto &result : resultList)
1125 processedResultList.append(processPickResult(result));
1127 return processedResultList;
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142QList<QQuick3DPickResult> QQuick3DViewport::pickAll(
float x,
float y)
const
1144 QQuick3DSceneRenderer *renderer = getRenderer();
1146 return QList<QQuick3DPickResult>();
1148 const QPointF position(qreal(x) * window()->effectiveDevicePixelRatio() * m_widthMultiplier,
1149 qreal(y) * window()->effectiveDevicePixelRatio() * m_heightMultiplier);
1150 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(position);
1151 if (!rayResult.has_value())
1152 return QList<QQuick3DPickResult>();
1154 const auto resultList = renderer->syncPickAll(rayResult.value());
1155 QList<QQuick3DPickResult> processedResultList;
1156 processedResultList.reserve(resultList.size());
1157 for (
const auto &result : resultList)
1158 processedResultList.append(processPickResult(result));
1160 return processedResultList;
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction)
const
1178 QQuick3DSceneRenderer *renderer = getRenderer();
1180 return QQuick3DPickResult();
1182 const QSSGRenderRay ray(origin, direction);
1183 const auto resultList = renderer->syncPick(ray);
1184 return getNearestPickResult(resultList);
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203QList<QQuick3DPickResult> QQuick3DViewport::rayPickAll(
const QVector3D &origin,
const QVector3D &direction)
const
1205 QQuick3DSceneRenderer *renderer = getRenderer();
1207 return QList<QQuick3DPickResult>();
1209 const QSSGRenderRay ray(origin, direction);
1211 const auto resultList = renderer->syncPickAll(ray);
1212 QList<QQuick3DPickResult> processedResultList;
1213 processedResultList.reserve(resultList.size());
1214 for (
const auto &result : resultList) {
1215 auto processedResult = processPickResult(result);
1216 if (processedResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1217 processedResultList.append(processedResult);
1220 return processedResultList;
1224
1225
1226
1227
1228
1229
1230
1231QQuick3DPickResult QQuick3DViewport::rayPick(
const QVector3D &origin,
const QVector3D &direction, QQuick3DModel *model)
const
1233 QQuick3DSceneRenderer *renderer = getRenderer();
1235 return QQuick3DPickResult();
1237 const QSSGRenderRay ray(origin, direction);
1239 const auto renderNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(model)->spatialNode);
1240 const auto resultList = renderer->syncPickOne(ray, renderNode);
1241 return getNearestPickResult(resultList);
1244void QQuick3DViewport::processPointerEventFromRay(
const QVector3D &origin,
const QVector3D &direction, QPointerEvent *event)
const
1246 internalPick(event, origin, direction);
1253class SyntheticTouchDevice :
public QPointingDevice
1256 SyntheticTouchDevice(QObject *parent =
nullptr)
1257 : QPointingDevice(QLatin1StringView(
"QtQuick3D Touch Synthesizer"),
1259 DeviceType::TouchScreen,
1260 PointerType::Finger,
1261 Capability::Position,
1263 QString(), QPointingDeviceUniqueId(),
1271
1272
1273
1274
1275
1276
1277
1278
1279
1281void QQuick3DViewport::setTouchpoint(QQuickItem *target,
const QPointF &position,
int pointId,
bool pressed)
1283 if (pointId >= m_touchState.size())
1284 m_touchState.resize(pointId + 1);
1285 auto prevState = m_touchState[pointId];
1287 const bool sameTarget = prevState.target == target;
1288 const bool wasPressed = prevState.isPressed;
1290 const bool isPress = pressed && (!sameTarget || !wasPressed);
1291 const bool isRelease = !pressed && wasPressed && sameTarget;
1296 if (!sameTarget && wasPressed)
1297 qWarning(
"QQuick3DViewport::setTouchpoint missing release event");
1299 if (!pressed && !wasPressed) {
1304 m_touchState[pointId] = { target, position, pressed };
1306 if (!m_syntheticTouchDevice)
1307 m_syntheticTouchDevice =
new SyntheticTouchDevice(
this);
1309 QPointingDevicePrivate *devPriv = QPointingDevicePrivate::get(m_syntheticTouchDevice);
1311 auto makePoint = [devPriv](
int id, QEventPoint::State pointState, QPointF pos) -> QEventPoint {
1312 auto epd = devPriv->pointById(id);
1313 auto &ep = epd->eventPoint;
1314 if (pointState != QEventPoint::State::Stationary)
1315 ep.setAccepted(
false);
1317 auto res = QMutableEventPoint::withTimeStamp(0, id, pointState, pos, pos, pos);
1318 QMutableEventPoint::update(res, ep);
1322 auto sendTouchEvent = [&](QQuickItem *t,
const QPointF &position,
int pointId, QEventPoint::State pointState) ->
void {
1323 QList<QEventPoint> points;
1324 bool otherPoint =
false;
1325 for (
int i = 0; i < m_touchState.size(); ++i) {
1326 const auto &ts = m_touchState[i];
1330 auto newPoint = makePoint(i, pointState, position);
1332 }
else if (ts.isPressed) {
1334 points << makePoint(i, QEventPoint::Stationary, ts.position);
1339 if (pointState == QEventPoint::Pressed && !otherPoint)
1340 type = QEvent::Type::TouchBegin;
1341 else if (pointState == QEventPoint::Released && !otherPoint)
1342 type = QEvent::Type::TouchEnd;
1344 type = QEvent::Type::TouchUpdate;
1346 QTouchEvent ev(type, m_syntheticTouchDevice, {}, points);
1350 auto da = QQuickItemPrivate::get(t)->deliveryAgent();
1351 bool handled = da->event(&ev);
1356 if (ev.isEndEvent()) {
1357 for (
auto &point : ev.points()) {
1358 if (point.state() == QEventPoint::State::Released) {
1359 ev.setExclusiveGrabber(point,
nullptr);
1360 ev.clearPassiveGrabbers(point);
1367 if (prevState.target && !sameTarget)
1368 sendTouchEvent(prevState.target, prevState.position, pointId, QEventPoint::Released);
1371 QEventPoint::State newState = isPress ? QEventPoint::Pressed : isRelease ? QEventPoint::Released : QEventPoint::Updated;
1372 sendTouchEvent(target, position, pointId, newState);
1375QQuick3DLightmapBaker *QQuick3DViewport::maybeLightmapBaker()
1377 return m_lightmapBaker;
1380QQuick3DLightmapBaker *QQuick3DViewport::lightmapBaker()
1382 if (!m_lightmapBaker)
1383 m_lightmapBaker=
new QQuick3DLightmapBaker(
this);
1385 return m_lightmapBaker;
1389
1390
1391void QQuick3DViewport::bakeLightmap()
1393 QQuick3DSceneRenderer *renderer = getRenderer();
1394 if (!renderer || !renderer->m_layer->renderData)
1397 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1399 if (!currentlyBaking)
1400 lightmapBaker()->bake();
1404
1405
1406void QQuick3DViewport::denoiseLightmap()
1408 QQuick3DSceneRenderer *renderer = getRenderer();
1409 if (!renderer || !renderer->m_layer->renderData)
1412 const bool currentlyBaking = renderer->m_layer->renderData->lightmapBaker !=
nullptr;
1414 if (!currentlyBaking)
1415 lightmapBaker()->denoise();
1419void QQuick3DViewport::setGlobalPickingEnabled(
bool isEnabled)
1421 QQuick3DSceneRenderer *renderer = getRenderer();
1425 renderer->setGlobalPickingEnabled(isEnabled);
1428void QQuick3DViewport::invalidateSceneGraph()
1433QQuick3DSceneRenderer *QQuick3DViewport::getRenderer()
const
1435 QQuick3DSceneRenderer *renderer =
nullptr;
1437 renderer = m_node->renderer;
1438 }
else if (m_renderNode) {
1439 renderer = m_renderNode->renderer;
1440 }
else if (m_directRenderer) {
1441 renderer = m_directRenderer->renderer();
1446void QQuick3DViewport::updateDynamicTextures()
1451 const auto &sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
1452 for (
auto *texture : std::as_const(sceneManager->qsgDynamicTextures))
1453 texture->updateTexture();
1455 QQuick3DNode *scene = m_importScene;
1457 const auto &importSm = QQuick3DObjectPrivate::get(scene)->sceneManager;
1458 if (importSm != sceneManager) {
1459 for (
auto *texture : std::as_const(importSm->qsgDynamicTextures))
1460 texture->updateTexture();
1464 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
1465 scene = rn ? rn->view3D()->importScene() :
nullptr;
1469QSGNode *QQuick3DViewport::setupOffscreenRenderer(QSGNode *node)
1471 SGFramebufferObjectNode *n =
static_cast<SGFramebufferObjectNode *>(node);
1475 m_node =
new SGFramebufferObjectNode;
1480 n->window = window();
1481 n->renderer = createRenderer();
1484 n->renderer->fboNode = n;
1486 connect(window(), SIGNAL(screenChanged(QScreen*)), n, SLOT(handleScreenChange()));
1489 const qreal dpr = window()->effectiveDevicePixelRatio();
1490 const QSize minFboSize = QQuickItemPrivate::get(
this)->sceneGraphContext()->minimumFBOSize();
1491 QSize desiredFboSize = QSize(m_explicitTextureWidth, m_explicitTextureHeight);
1492 if (desiredFboSize.isEmpty()) {
1493 desiredFboSize = QSize(width(), height()) * dpr;
1494 n->devicePixelRatio = dpr;
1496 m_widthMultiplier = 1.0f;
1497 m_heightMultiplier = 1.0f;
1499 QSize itemPixelSize = QSize(width(), height()) * dpr;
1501 m_widthMultiplier = desiredFboSize.width() /
float(itemPixelSize.width());
1502 m_heightMultiplier = desiredFboSize.height() /
float(itemPixelSize.height());
1503 n->devicePixelRatio = 1.0;
1505 desiredFboSize.setWidth(qMax(minFboSize.width(), desiredFboSize.width()));
1506 desiredFboSize.setHeight(qMax(minFboSize.height(), desiredFboSize.height()));
1508 if (desiredFboSize != m_effectiveTextureSize) {
1509 m_effectiveTextureSize = desiredFboSize;
1510 emit effectiveTextureSizeChanged();
1513 n->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
1514 n->setRect(0, 0, width(), height());
1515 if (checkIsVisible() && isComponentComplete()) {
1516 n->renderer->synchronize(
this, desiredFboSize, n->devicePixelRatio);
1517 if (n->renderer->m_textureNeedsFlip)
1518 n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
1519 updateDynamicTextures();
1520 n->scheduleRender();
1526QSGNode *QQuick3DViewport::setupInlineRenderer(QSGNode *node)
1528 QQuick3DSGRenderNode *n =
static_cast<QQuick3DSGRenderNode *>(node);
1531 m_renderNode =
new QQuick3DSGRenderNode;
1536 n->window = window();
1537 n->renderer = createRenderer();
1542 if (!m_effectiveTextureSize.isEmpty()) {
1543 m_effectiveTextureSize = QSize();
1544 emit effectiveTextureSizeChanged();
1547 const QSize targetSize = window()->effectiveDevicePixelRatio() * QSize(width(), height());
1552 if (checkIsVisible() && isComponentComplete()) {
1553 n->renderer->synchronize(
this, targetSize, window()->effectiveDevicePixelRatio());
1554 updateDynamicTextures();
1555 n->markDirty(QSGNode::DirtyMaterial);
1562void QQuick3DViewport::setupDirectRenderer(RenderMode mode)
1564 auto renderMode = (mode == Underlay) ? QQuick3DSGDirectRenderer::Underlay
1565 : QQuick3DSGDirectRenderer::Overlay;
1566 if (!m_directRenderer) {
1567 QQuick3DSceneRenderer *sceneRenderer = createRenderer();
1570 m_directRenderer =
new QQuick3DSGDirectRenderer(sceneRenderer, window(), renderMode);
1571 connect(window(), &QQuickWindow::sceneGraphInvalidated,
this, &QQuick3DViewport::cleanupDirectRenderer, Qt::DirectConnection);
1574 if (!m_effectiveTextureSize.isEmpty()) {
1575 m_effectiveTextureSize = QSize();
1576 emit effectiveTextureSizeChanged();
1579 const QSizeF targetSize = window()->effectiveDevicePixelRatio() * QSizeF(width(), height());
1580 m_directRenderer->setViewport(QRectF(window()->effectiveDevicePixelRatio() * mapToScene(QPointF(0, 0)), targetSize));
1581 m_directRenderer->setVisibility(isVisible());
1583 m_directRenderer->preSynchronize();
1584 m_directRenderer->renderer()->synchronize(
this, targetSize.toSize(), window()->effectiveDevicePixelRatio());
1585 updateDynamicTextures();
1586 m_directRenderer->requestRender();
1592bool QQuick3DViewport::checkIsVisible()
const
1594 auto childPrivate = QQuickItemPrivate::get(
this);
1595 return (childPrivate->explicitVisible ||
1596 (childPrivate->extra.isAllocated() && childPrivate->extra->effectRefCount));
1601
1602
1603
1604
1605
1606
1607
1608
1609void QQuick3DViewport::processPickedObject(
const QSSGRenderPickResult &pickResult,
1611 QPointerEvent *event,
1612 QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1614 QQuickItem *subsceneRootItem =
nullptr;
1615 QPointF subscenePosition;
1616 const auto backendObject = pickResult.m_hitObject;
1617 const auto frontendObject = findFrontendNode(backendObject);
1618 if (!frontendObject)
1624 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1625 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1628 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1630 subsceneRootItem = item2D->contentItem();
1631 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1635 subscenePosition = pickResult.m_localUVCoords.toPointF();
1639 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1641 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1643 int materialSubset = pickResult.m_subset;
1644 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1646 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1647 materialSubset = backendModel->materials.size() - 1;
1648 if (materialSubset < 0)
1650 const auto backendMaterial = backendModel->materials.at(materialSubset);
1651 const auto frontendMaterial =
static_cast<QQuick3DMaterial*>(findFrontendNode(backendMaterial));
1652 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1654 if (subsceneRootItem) {
1656 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1657 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1662 if (subsceneRootItem) {
1663 SubsceneInfo &subscene = visitedSubscenes[subsceneRootItem];
1664 subscene.obj = frontendObject;
1665 if (subscene.eventPointScenePositions.size() != event->pointCount()) {
1667 constexpr QPointF inf(-qt_inf(), -qt_inf());
1668 subscene.eventPointScenePositions.resize(event->pointCount(), inf);
1670 subscene.eventPointScenePositions[pointIndex] = subscenePosition;
1675
1676
1677
1678
1679
1680
1681
1682
1684QQuickItem *QQuick3DViewport::getSubSceneRootItem(QQuick3DMaterial *material)
const
1689 QQuickItem *subsceneRootItem =
nullptr;
1690 const auto frontendMaterialPrivate = QQuick3DObjectPrivate::get(material);
1692 if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::DefaultMaterial) {
1694 const auto defaultMaterial = qobject_cast<QQuick3DDefaultMaterial *>(material);
1695 if (defaultMaterial) {
1697 if (defaultMaterial->diffuseMap() && defaultMaterial->diffuseMap()->sourceItem())
1698 subsceneRootItem = defaultMaterial->diffuseMap()->sourceItem();
1701 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::PrincipledMaterial) {
1703 const auto principledMaterial = qobject_cast<QQuick3DPrincipledMaterial *>(material);
1704 if (principledMaterial) {
1706 if (principledMaterial->baseColorMap() && principledMaterial->baseColorMap()->sourceItem())
1707 subsceneRootItem = principledMaterial->baseColorMap()->sourceItem();
1709 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::SpecularGlossyMaterial) {
1711 const auto specularGlossyMaterial = qobject_cast<QQuick3DSpecularGlossyMaterial *>(material);
1712 if (specularGlossyMaterial) {
1714 if (specularGlossyMaterial->albedoMap() && specularGlossyMaterial->albedoMap()->sourceItem())
1715 subsceneRootItem = specularGlossyMaterial->albedoMap()->sourceItem();
1717 }
else if (frontendMaterialPrivate->type == QQuick3DObjectPrivate::Type::CustomMaterial) {
1719 const auto customMaterial = qobject_cast<QQuick3DCustomMaterial *>(material);
1720 if (customMaterial) {
1722 const auto &texturesInputs = customMaterial->m_dynamicTextureMaps;
1723 for (
const auto &textureInput : texturesInputs) {
1724 if (
auto texture = textureInput->texture()) {
1725 if (texture->sourceItem()) {
1726 subsceneRootItem = texture->sourceItem();
1733 return subsceneRootItem;
1738
1739
1740QQuick3DPickResult QQuick3DViewport::getNearestPickResult(
const QVarLengthArray<QSSGRenderPickResult, 20> &pickResults)
const
1742 for (
const auto &result : pickResults) {
1743 auto pickResult = processPickResult(result);
1744 if (pickResult.hitType() != QQuick3DPickResultEnums::HitType::Null)
1748 return QQuick3DPickResult();
1752
1753
1754
1755
1756
1757bool QQuick3DViewport::forwardEventToSubscenes(QPointerEvent *event,
1759 QQuick3DSceneRenderer *renderer,
1760 const QFlatMap<QQuickItem *, SubsceneInfo> &visitedSubscenes)
const
1767 QVarLengthArray<QPointF, 16> originalScenePositions;
1768 originalScenePositions.resize(event->pointCount());
1769 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1770 originalScenePositions[pointIndex] = event->point(pointIndex).scenePosition();
1771 for (
auto subscene : visitedSubscenes) {
1772 QQuickItem *subsceneRoot = subscene.first;
1773 auto &subsceneInfo = subscene.second;
1774 Q_ASSERT(subsceneInfo.eventPointScenePositions.size() == event->pointCount());
1775 auto da = QQuickItemPrivate::get(subsceneRoot)->deliveryAgent();
1776 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1777 const auto &pt = subsceneInfo.eventPointScenePositions.at(pointIndex);
1782 QEventPoint &ep = event->point(pointIndex);
1783 QMutableEventPoint::setPosition(ep, pt);
1784 QMutableEventPoint::setScenePosition(ep, pt);
1787 if (event->isBeginEvent())
1788 da->setSceneTransform(
nullptr);
1789 if (da->event(event)) {
1791 if (QQuickDeliveryAgentPrivate::anyPointGrabbed(event) && !useRayPicking) {
1796 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(subsceneInfo.obj);
1797 const bool item2Dcase = (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D);
1798 ViewportTransformHelper *transform =
new ViewportTransformHelper;
1799 transform->viewport =
const_cast<QQuick3DViewport *>(
this);
1800 transform->renderer = renderer;
1801 transform->sceneParentNode =
static_cast<QSSGRenderNode*>(frontendObjectPrivate->spatialNode);
1802 transform->targetItem = subsceneRoot;
1803 transform->scaleX = window()->effectiveDevicePixelRatio() * m_widthMultiplier;
1804 transform->scaleY = window()->effectiveDevicePixelRatio() * m_heightMultiplier;
1805 transform->uvCoordsArePixels = item2Dcase;
1806 transform->setOnDeliveryAgent(da);
1807 qCDebug(lcPick) << event->type() <<
"created ViewportTransformHelper on" << da;
1809 }
else if (event->type() != QEvent::HoverMove) {
1810 qCDebug(lcPick) << subsceneRoot <<
"didn't want" << event;
1812 event->setAccepted(
false);
1814 if (visitedSubscenes.isEmpty()) {
1815 event->setAccepted(
false);
1817 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex)
1818 QMutableEventPoint::setScenePosition(event->point(pointIndex), originalScenePositions.at(pointIndex));
1824 if (event->isEndEvent() && useRayPicking) {
1825 if (event->isSinglePointEvent()) {
1826 if (
static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton) {
1827 auto &firstPt = event->point(0);
1828 event->setExclusiveGrabber(firstPt,
nullptr);
1829 event->clearPassiveGrabbers(firstPt);
1832 for (
auto &point : event->points()) {
1833 if (point.state() == QEventPoint::State::Released) {
1834 event->setExclusiveGrabber(point,
nullptr);
1835 event->clearPassiveGrabbers(point);
1845bool QQuick3DViewport::internalPick(QPointerEvent *event,
const QVector3D &origin,
const QVector3D &direction)
const
1847 QQuick3DSceneRenderer *renderer = getRenderer();
1848 if (!renderer || !event)
1851 QFlatMap<QQuickItem*, SubsceneInfo> visitedSubscenes;
1852 const bool useRayPicking = !direction.isNull();
1854 for (
int pointIndex = 0; pointIndex < event->pointCount(); ++pointIndex) {
1855 auto &eventPoint = event->point(pointIndex);
1856 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
1857 if (Q_UNLIKELY(useRayPicking))
1858 pickResults = getPickResults(renderer, origin, direction);
1860 pickResults = getPickResults(renderer, eventPoint);
1862 if (!pickResults.isEmpty())
1863 for (
const auto &pickResult : pickResults)
1864 processPickedObject(pickResult, pointIndex, event, visitedSubscenes);
1866 eventPoint.setAccepted(
false);
1869 return forwardEventToSubscenes(event, useRayPicking, renderer, visitedSubscenes);
1872bool QQuick3DViewport::singlePointPick(QSinglePointEvent *event,
const QVector3D &origin,
const QVector3D &direction)
1874 QQuick3DSceneRenderer *renderer = getRenderer();
1875 if (!renderer || !event)
1878 QSSGRenderRay ray(origin, direction);
1880 Q_ASSERT(event->pointCount() == 1);
1881 QPointF originalPosition = event->point(0).scenePosition();
1883 auto pickResults = renderer->syncPickAll(ray);
1885 bool delivered =
false;
1887 constexpr float jitterLimit = 2.5;
1888 bool withinJitterLimit =
false;
1890 for (
const auto &pickResult : pickResults) {
1891 auto [item, position] = getItemAndPosition(pickResult);
1894 if (item == m_prevMouseItem && (position - m_prevMousePos).manhattanLength() < jitterLimit && !event->button()) {
1895 withinJitterLimit =
true;
1898 auto da = QQuickItemPrivate::get(item)->deliveryAgent();
1899 QEventPoint &ep = event->point(0);
1900 QMutableEventPoint::setPosition(ep, position);
1901 QMutableEventPoint::setScenePosition(ep, position);
1902 if (da->event(event)) {
1904 if (event->type() == QEvent::MouseButtonPress) {
1905 m_prevMouseItem = item;
1906 m_prevMousePos = position;
1907 withinJitterLimit =
true;
1913 QMutableEventPoint::setScenePosition(event->point(0), originalPosition);
1914 if (!withinJitterLimit)
1915 m_prevMouseItem =
nullptr;
1920 if (event->isEndEvent()) {
1921 if (event->buttons() == Qt::NoButton) {
1922 auto &firstPt = event->point(0);
1923 event->setExclusiveGrabber(firstPt,
nullptr);
1924 event->clearPassiveGrabbers(firstPt);
1931QPair<QQuickItem *, QPointF> QQuick3DViewport::getItemAndPosition(
const QSSGRenderPickResult &pickResult)
1933 QQuickItem *subsceneRootItem =
nullptr;
1934 QPointF subscenePosition;
1935 const auto backendObject = pickResult.m_hitObject;
1936 const auto frontendObject = findFrontendNode(backendObject);
1937 if (!frontendObject)
1939 auto frontendObjectPrivate = QQuick3DObjectPrivate::get(frontendObject);
1940 if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Item2D) {
1943 auto item2D = qobject_cast<QQuick3DItem2D *>(frontendObject);
1945 subsceneRootItem = item2D->contentItem();
1946 if (!subsceneRootItem || subsceneRootItem->childItems().isEmpty())
1950 subscenePosition = pickResult.m_localUVCoords.toPointF();
1954 if (!subsceneRootItem->childAt(subscenePosition.x(), subscenePosition.y()))
1956 }
else if (frontendObjectPrivate->type == QQuick3DObjectPrivate::Type::Model) {
1958 int materialSubset = pickResult.m_subset;
1959 const auto backendModel =
static_cast<
const QSSGRenderModel *>(backendObject);
1961 if (backendModel->materials.size() < (pickResult.m_subset + 1))
1962 materialSubset = backendModel->materials.size() - 1;
1963 if (materialSubset < 0)
1965 const auto backendMaterial = backendModel->materials.at(materialSubset);
1966 const auto frontendMaterial =
static_cast<QQuick3DMaterial *>(findFrontendNode(backendMaterial));
1967 subsceneRootItem = getSubSceneRootItem(frontendMaterial);
1969 if (subsceneRootItem) {
1971 subscenePosition = QPointF(subsceneRootItem->x() + pickResult.m_localUVCoords.x() * subsceneRootItem->width(),
1972 subsceneRootItem->y() - pickResult.m_localUVCoords.y() * subsceneRootItem->height() + subsceneRootItem->height());
1975 return {subsceneRootItem, subscenePosition};
1978QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
1979 const QVector3D &origin,
1980 const QVector3D &direction)
const
1982 const QSSGRenderRay ray(origin, direction);
1983 return renderer->syncPickAll(ray);
1986QVarLengthArray<QSSGRenderPickResult, 20> QQuick3DViewport::getPickResults(QQuick3DSceneRenderer *renderer,
const QEventPoint &eventPoint)
const
1988 QVarLengthArray<QSSGRenderPickResult, 20> pickResults;
1989 QPointF realPosition = eventPoint.position() * window()->effectiveDevicePixelRatio();
1991 realPosition.rx() *= m_widthMultiplier;
1992 realPosition.ry() *= m_heightMultiplier;
1993 std::optional<QSSGRenderRay> rayResult = renderer->getRayFromViewportPos(realPosition);
1994 if (rayResult.has_value())
1995 pickResults = renderer->syncPickAll(rayResult.value());
2000
2001
2002
2003
2004
2005QQuick3DObject *QQuick3DViewport::findFrontendNode(
const QSSGRenderGraphObject *backendObject)
const
2010 const auto sceneManager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2011 QQuick3DObject *frontendObject = sceneManager->lookUpNode(backendObject);
2012 if (!frontendObject && m_importScene) {
2013 const auto importSceneManager = QQuick3DObjectPrivate::get(m_importScene)->sceneManager;
2014 frontendObject = importSceneManager->lookUpNode(backendObject);
2016 return frontendObject;
2019QQuick3DPickResult QQuick3DViewport::processPickResult(
const QSSGRenderPickResult &pickResult)
const
2021 if (!pickResult.m_hitObject)
2022 return QQuick3DPickResult();
2024 QQuick3DObject *frontendObject = findFrontendNode(pickResult.m_hitObject);
2026 QQuick3DModel *model = qobject_cast<QQuick3DModel *>(frontendObject);
2028 return QQuick3DPickResult(model,
2029 ::sqrtf(pickResult.m_distanceSq),
2030 pickResult.m_localUVCoords,
2031 pickResult.m_scenePosition,
2032 pickResult.m_localPosition,
2033 pickResult.m_faceNormal,
2034 pickResult.m_sceneNormal,
2035 pickResult.m_instanceIndex);
2037 QQuick3DItem2D *frontend2DItem = qobject_cast<QQuick3DItem2D *>(frontendObject);
2038 if (frontend2DItem && frontend2DItem->contentItem()) {
2040 const QPointF subscenePosition = pickResult.m_localUVCoords.toPointF();
2041 const auto child = frontend2DItem->contentItem()->childAt(subscenePosition.x(), subscenePosition.y());
2043 return QQuick3DPickResult(child,
2044 ::sqrtf(pickResult.m_distanceSq),
2045 QVector2D(frontend2DItem->contentItem()->mapToItem(child, subscenePosition)),
2046 pickResult.m_scenePosition,
2047 pickResult.m_localPosition,
2048 pickResult.m_faceNormal);
2052 return QQuick3DPickResult();
2057QQuick3DSceneManager *QQuick3DViewport::findChildSceneManager(QQuick3DObject *inObject, QQuick3DSceneManager *manager)
2062 auto children = QQuick3DObjectPrivate::get(inObject)->childItems;
2063 for (
auto child : children) {
2064 if (
auto m = QQuick3DObjectPrivate::get(child)->sceneManager) {
2068 manager = findChildSceneManager(child, manager);
2073void QQuick3DViewport::updateInputProcessing()
2076 setAcceptTouchEvents(m_enableInputProcessing);
2077 setAcceptHoverEvents(m_enableInputProcessing);
2078 setAcceptedMouseButtons(m_enableInputProcessing ? Qt::AllButtons : Qt::NoButton);
2081void QQuick3DViewport::onReleaseCachedResources()
2083 if (
auto renderer = getRenderer())
2084 renderer->releaseCachedResources();
2088
2089
2090
2091
2092
2093
2094QQmlListProperty<QQuick3DObject> QQuick3DViewport::extensions()
2096 return QQmlListProperty<QQuick3DObject>{
this,
2097 &m_extensionListDirty,
2098 &QQuick3DExtensionListHelper::extensionAppend,
2099 &QQuick3DExtensionListHelper::extensionCount,
2100 &QQuick3DExtensionListHelper::extensionAt,
2101 &QQuick3DExtensionListHelper::extensionClear,
2102 &QQuick3DExtensionListHelper::extensionReplace,
2103 &QQuick3DExtensionListHelper::extensionRemoveLast};
2107
2108
2109void QQuick3DViewport::rebuildExtensionList()
2111 m_extensionListDirty =
true;
2116
2117
2118
2119
2120
2121QQuick3DViewport::QQuick3DViewport(PrivateInstanceType type, QQuickItem *parent)
2122 : QQuick3DViewport(parent)
2124 m_isXrViewInstance = type == PrivateInstanceType::XrViewInstance;
2127void QQuick3DViewport::updateCameraForLayer(
const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode)
2129 layerNode.explicitCameras.clear();
2130 if (!view3D.m_multiViewCameras.isEmpty()) {
2131 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
2132 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
2133 }
else if (view3D.camera()) {
2134 layerNode.explicitCameras.append(
static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode));
2139 for (QSSGRenderCamera *camera : std::as_const(layerNode.explicitCameras)) {
2140 if (!camera->parent)
2141 layerNode.addChild(*camera);
2145void QQuick3DViewport::updateSceneManagerForImportScene()
2147 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2148 if (!privateObject->sceneManager) {
2150 QQuick3DSceneManager *manager = findChildSceneManager(m_importScene);
2153 manager = QQuick3DObjectPrivate::get(m_sceneRoot)->sceneManager;
2155 manager->setWindow(window());
2156 privateObject->refSceneManager(*manager);
2161 if (!privateObject->sceneManager)
2165 connect(privateObject->sceneManager, &QQuick3DSceneManager::needsUpdate,
2166 this, &QQuickItem::update, Qt::UniqueConnection);
2167 connect(privateObject->sceneManager, &QObject::destroyed,
2168 this, [&](QObject *) {
2169 auto privateObject = QQuick3DObjectPrivate::get(m_importScene);
2170 privateObject->sceneManager =
nullptr;
2171 updateSceneManagerForImportScene();
2172 }, Qt::DirectConnection);
2174 QQuick3DNode *scene = m_importScene;
2176 QQuick3DSceneRootNode *rn = qobject_cast<QQuick3DSceneRootNode *>(scene);
2177 scene = rn ? rn->view3D()->importScene() :
nullptr;
2180 connect(QQuick3DObjectPrivate::get(scene)->sceneManager,
2181 &QQuick3DSceneManager::needsUpdate,
2182 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)
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)