Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3dxrmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <QtCore/QCoreApplication>
7#include <QtCore/QDebug>
8#include <QtCore/qjsonobject.h>
9#include <QtCore/qjsonarray.h>
10
11#include <rhi/qrhi.h>
12
13#include <QtQuick/private/qquickwindow_p.h>
14#include <QtQuick/QQuickRenderControl>
15#include <QtQuick/QQuickRenderTarget>
16#include <QtQuick/QQuickItem>
17
18#include <QtQuick3D/private/qquick3dnode_p.h>
19#include <QtQuick3D/private/qquick3dviewport_p.h>
20
21
22// #include "qquick3dxrcamera_p.h"
24
25#if defined(Q_OS_VISIONOS)
26# include <QtQuick3DXr/private/qquick3dxrmanager_visionos_p.h>
27#else
29#endif
30
31#include "qquick3dxrorigin_p.h"
33
35
36
42
44{
45 teardown();
46
47 // maintain the correct order
48 delete m_vrViewport;
49 delete m_quickWindow;
50 delete m_renderControl;
51 delete m_animationDriver;
52}
53
55{
56 Q_D(const QQuick3DXrManager);
57 return d->isReady();
58}
59
61{
63
64 QString m_errorString;
65
66 // TODO: Handle visionos being async a bit better
67 if (!d->initialize()) {
68 if (!d->isReady())
69 m_errorString = QStringLiteral("Waiting for the renderer to start.");
70 else
71 m_errorString = QStringLiteral("Failed to initialize the XR manager.");
72
73 return false;
74 }
75
76 // Setup Graphics
77 return setupGraphics();
78}
79
81{
83 d->teardown();
84}
85
87{
88 Q_D(const QQuick3DXrManager);
89 return d->isValid();
90}
91
93{
95 d->setPassthroughEnabled(enabled);
96}
97
99{
100 Q_D(const QQuick3DXrManager);
101 return d->isPassthroughEnabled();
102}
103
105{
107 d->setMultiviewRenderingEnabled(enable);
108}
109
111{
112 Q_D(const QQuick3DXrManager);
113 return d->isMultiViewRenderingEnabled();
114}
115
117{
118 Q_D(const QQuick3DXrManager);
119 return d->isMultiViewRenderingSupported();
120}
121
123{
124#if defined(Q_OS_VISIONOS)
125 // Foveation is not configurable on VisionOS
127#else
128 Q_D(const QQuick3DXrManager);
129 return QtQuick3DXr::FoveationLevel(d->m_foveationLevel);
130#endif
131}
132
134{
135#if defined(Q_OS_VISIONOS)
136 // Foveation is not configurable on VisionOS
138#else
140 const XrFoveationLevelFB xrLevel = XrFoveationLevelFB(level);
141 if (d->m_foveationLevel == xrLevel)
142 return;
143
144 d->m_foveationLevel = xrLevel;
145 d->setupMetaQuestFoveation();
146#endif
147}
148
150{
151 Q_D(const QQuick3DXrManager);
152 return d->getReferenceSpace();
153}
154
156{
158
159 d->setReferenceSpace(newReferenceSpace);
160}
161
163{
164 Q_D(const QQuick3DXrManager);
165 return d->isDepthSubmissionEnabled();
166}
167
169{
171 d->setDepthSubmissionEnabled(enable);
172}
173
175{
176 Q_D(const QQuick3DXrManager);
177 return d->errorString();
178}
179
181{
183 d->setSamples(samples);
184}
185
186void QQuick3DXrManager::update()
187{
190}
191
192void QQuick3DXrManager::processSpatialEvents(const QJsonObject &events)
193{
194 static qint64 lastId = -1;
195
196 QJsonArray eventArray = events.value(QStringLiteral("events")).toArray();
197 for (const auto &event : eventArray) {
198 QJsonObject eventObj = event.toObject();
199 // qDebug() << eventObj;
200
201 // ID (unique per event)
202 const qint64 id = eventObj.value(QStringLiteral("id")).toDouble();
203 // timestamp (in seconds)
204 //const double timestamp = eventObj.value(QStringLiteral("timestamp")).toDouble();
205 // kind
206 const QString kind = eventObj.value(QStringLiteral("kind")).toString();
207 if (kind != QStringLiteral("indirectPinch"))
208 qWarning() << "kind is " << kind << "!";
209
210
211 // phase
212 const QString phase = eventObj.value(QStringLiteral("phase")).toString();
213
214 // selectionRay (check if exists first)
215 QJsonObject selectionRayObj = eventObj.value(QStringLiteral("selectionRay")).toObject();
216 if (!selectionRayObj.isEmpty()) {
217 // origin
218 QJsonObject originObj = selectionRayObj.value(QStringLiteral("origin")).toObject();
219 QVector3D origin(originObj.value(QStringLiteral("x")).toDouble(), originObj.value(QStringLiteral("y")).toDouble(), originObj.value(QStringLiteral("z")).toDouble());
220 // convert meters to cm
221 origin *= 100.0;
222
223 // direction
224 QJsonObject directionObj = selectionRayObj.value(QStringLiteral("direction")).toObject();
225 QVector3D direction(directionObj.value(QStringLiteral("x")).toDouble(), directionObj.value(QStringLiteral("y")).toDouble(), directionObj.value(QStringLiteral("z")).toDouble());
226
227 QEvent::Type eventType;
228
229 if (phase == QStringLiteral("active")) {
230 if (lastId != id) {
231 // Press
232 lastId = id;
233 eventType = QEvent::MouseButtonPress;
234 } else {
235 // Move
236 eventType = QEvent::MouseMove;
237 }
238 } else {
239 // Release
240 lastId = -1;
241 eventType = QEvent::MouseButtonRelease;
242 }
243
245 m_vrViewport->processPointerEventFromRay(origin, direction, event);
246 delete event;
247 }
248 }
249 // An example of the input data
250 // {
251 // "id":4404736049417834088,
252 // "inputDevicePose": {
253 // "altitude":0,
254 // "azimuth":1.5707963267948966,
255 // "pose3D":{
256 // "position":{
257 // "x":0.227996826171875,
258 // "y":0.957000732421875,
259 // "z":-0.55999755859375
260 // },
261 // "rotation":{
262 // "vector":[0,0,0,1]
263 // }
264 // }
265 // },
266 // "kind":"indirectPinch",
267 // "location":[0,0],
268 // "location3D":{
269 // "x":0,
270 // "y":0,
271 // "z":0
272 // },
273 // "modifierKeys":0,
274 // "phase":"ended",
275 // "selectionRay":{
276 // "direction":{
277 // "x":0.3321685791015625,
278 // "y":0.25982666015625,
279 // "z":-0.9067230224609375
280 // },
281 // "origin":{
282 // "x":0.227996826171875,
283 // "y":0.957000732421875,
284 // "z":0
285 // }
286 // },
287 // "timestamp":74368.590710375
288 // }
289}
290
292{
294
295 if (e->type() == QEvent::UpdateRequest) {
296 d->processXrEvents();
297 update();
298 return true;
299 }
300 return QObject::event(e);
301}
302
303QQuick3DXrInputManager *QQuick3DXrManager::getInputManager() const
304{
305 Q_D(const QQuick3DXrManager);
306 return d->m_inputManager.data();
307}
308
309bool QQuick3DXrManager::setupGraphics()
310{
312
313 // FIXME: Should probably make sure we don't accidentally get here more then once
314 // or if we're re-initializing, in which case: make sure to clean up properly first.
315 if (d->isGraphicsInitialized())
316 return true;
317
318 preSetupQuickScene();
319
320 if (!d->setupGraphics(m_quickWindow))
321 return false;
322
323 if (!setupQuickScene())
324 return false;
325
326 QRhi *rhi = m_quickWindow->rhi();
327 QSSG_ASSERT_X(rhi != nullptr, "No RHI handle!", return false);
328
329 return d->finalizeGraphics(rhi);
330}
331
332void QQuick3DXrManager::renderFrame()
333{
335
336 checkOrigin();
337 d->doRenderFrame();
338}
339
340void QQuick3DXrManager::preSetupQuickScene()
341{
342 if (!m_renderControl)
343 m_renderControl = new QQuickRenderControl;
344 if (!m_quickWindow)
345 m_quickWindow = new QQuickWindow(m_renderControl);
346}
347
348bool QQuick3DXrManager::setupQuickScene()
349{
351
352 d->setupWindow(m_quickWindow);
353
354 if (!m_animationDriver) {
355 m_animationDriver = new QQuick3DXrAnimationDriver;
356 m_animationDriver->install();
357 }
358
359 const bool initSuccess = m_renderControl->initialize();
360 if (!initSuccess) {
361 qWarning("Quick 3D XR: Failed to create renderControl (failed to initialize RHI?)");
362 return false;
363 }
364
365 QRhi *rhi = m_renderControl->rhi();
366 if (!rhi) {
367 qWarning("Quick3D XR: No QRhi from renderControl. This should not happen.");
368 return false;
369 }
370
371 qDebug("Quick 3D XR: QRhi initialized with backend %s", rhi->backendName());
372
373 if (qEnvironmentVariableIntValue("QT_QUICK3D_XR_MULTIVIEW")) {
374 qDebug("Quick3D XR: multiview rendering requested via the environment");
376 }
377
378 return true;
379}
380
381void QQuick3DXrManager::checkOrigin()
382{
383 if (!m_xrOrigin) {
384 // Check the scene for an XrOrigin
385 std::function<QQuick3DXrOrigin*(QQuick3DObject *)> findOriginNode;
386 findOriginNode = [&findOriginNode](QQuick3DObject *node) -> QQuick3DXrOrigin *{
387 if (!node)
388 return nullptr;
389 auto origin = qobject_cast<QQuick3DXrOrigin *>(node);
390 if (origin)
391 return origin;
392 for (auto child : node->childItems()) {
393 origin = findOriginNode(child);
394 if (origin)
395 return origin;
396 }
397 return nullptr;
398 };
399 auto origin = findOriginNode(m_vrViewport->importScene());
400 if (origin) {
401 m_xrOrigin = origin;
403 connect(m_xrOrigin, &QObject::destroyed, this, [this](){
404 m_xrOrigin = nullptr;
406 });
407 }
408 }
409}
410
411bool QQuick3DXrManager::supportsPassthrough() const
412{
413 Q_D(const QQuick3DXrManager);
414 return d->supportsPassthrough();
415}
416
void install()
Installs this animation driver.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
Definition qcoreevent.h:45
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonPress
Definition qcoreevent.h:60
@ UpdateRequest
Definition qcoreevent.h:113
@ MouseButtonRelease
Definition qcoreevent.h:61
Type type() const
Returns the event type.
Definition qcoreevent.h:304
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
QJsonValue value(const QString &key) const
Returns a QJsonValue representing the value for the key key.
QJsonObject toObject() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QJsonArray toArray() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
double toDouble(double defaultValue=0) const
Converts the value to a double and returns it.
\inmodule QtGui
Definition qevent.h:196
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
\inmodule QtCore\reentrant
Definition qpoint.h:217
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
QQuick3DNode * importScene
void processPointerEventFromRay(const QVector3D &origin, const QVector3D &direction, QPointerEvent *event)
void setDepthSubmissionEnabled(bool enable)
bool isPassthroughEnabled() const
void setFixedFoveationLevel(QtQuick3DXr::FoveationLevel level)
bool isMultiViewRenderingSupported() const
QString errorString() const
QtQuick3DXr::FoveationLevel getFixedFoveationLevel() const
bool isDepthSubmissionEnabled() const
void setMultiviewRenderingEnabled(bool enable)
QQuick3DXrManager(QObject *parent=nullptr)
void setSamples(int samples)
void setPassthroughEnabled(bool enabled)
bool isMultiViewRenderingEnabled() const
void setReferenceSpace(QtQuick3DXr::ReferenceSpace newReferenceSpace)
bool event(QEvent *e) override
This virtual function receives events to an object and should return true if the event e was recogniz...
QtQuick3DXr::ReferenceSpace getReferenceSpace() const
The QQuickRenderControl class provides a mechanism for rendering the Qt Quick scenegraph onto an offs...
bool initialize()
Initializes the scene graph resources.
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1805
const char * backendName() const
Definition qrhi.cpp:8691
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
#define this
Definition dialogs.cpp:9
direction
Combined button and popup list for selecting options.
@ LeftButton
Definition qnamespace.h:58
@ NoModifier
#define qDebug
[1]
Definition qlogging.h:165
#define qWarning
Definition qlogging.h:167
GLsizei samples
GLenum GLuint GLint level
GLenum GLuint id
[7]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLboolean enable
struct _cl_event * event
#define QSSG_ASSERT_X(cond, msg, action)
#define QStringLiteral(str)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define emit
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
static double toDouble(Value v)
QLayoutItem * child
[0]
QNetworkRequest request(url)