1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dxrorigin_p.h" |
5 | |
6 | #include "qquick3dxrview_p.h" |
7 | |
8 | #include <QtQuick3D/private/qquick3dnode_p_p.h> |
9 | |
10 | #include <QtQuick3DUtils/private/qssgassert_p.h> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \qmltype XrOrigin |
16 | \inherits Node |
17 | \inqmlmodule QtQuick3D.Xr |
18 | \brief The origin location for the XrView. |
19 | |
20 | The origin determines the center of the \l{XrView::referenceSpace}{reference space}. |
21 | Changing the position of the origin will transport the user to a different position |
22 | in the scene. |
23 | |
24 | Most XR platforms allow the user to move physically, changing the viewpoint. This |
25 | does not change the position of the origin. To track the position of the headset, create |
26 | an XrCamera and assign it to the \l camera property. |
27 | |
28 | \warning Ensure you follow best practices when changing the position/rotation of |
29 | the origin. Not doing so may cause physical discomfort, nausea, or loss of balance. |
30 | In the worst case, this could lead to injury or even death. |
31 | */ |
32 | |
33 | QQuick3DXrOrigin::QQuick3DXrOrigin(QQuick3DNode *parent) |
34 | : QQuick3DNode(parent) |
35 | { |
36 | // These are the "real" cameras that are used for rendering. |
37 | QQuick3DXrEyeCamera *leftEyeCamera = new QQuick3DXrEyeCamera(this); |
38 | leftEyeCamera->setParentItem(this); |
39 | |
40 | QQuick3DXrEyeCamera *rightEyeCamera = new QQuick3DXrEyeCamera(this); |
41 | rightEyeCamera->setParentItem(this); |
42 | |
43 | m_eyeCameras = { leftEyeCamera, rightEyeCamera }; |
44 | } |
45 | |
46 | QQuick3DXrOrigin::~QQuick3DXrOrigin() |
47 | { |
48 | |
49 | } |
50 | |
51 | /*! |
52 | \qmlproperty XrCamera QtQuick3D.Xr::XrOrigin::camera |
53 | \brief Property for adding a tracked camera node. |
54 | |
55 | \default null |
56 | |
57 | Holds an XrCamera, which is a tracked spatial node that tracks the position and orientation |
58 | of the head-mounted display in the XR environment. |
59 | |
60 | \note This property is optional. |
61 | |
62 | \sa XrCamera |
63 | */ |
64 | |
65 | QQuick3DXrCamera *QQuick3DXrOrigin::camera() const |
66 | { |
67 | return m_camera; |
68 | } |
69 | |
70 | void QQuick3DXrOrigin::setCamera(QQuick3DXrCamera *newCamera) |
71 | { |
72 | if (m_camera == newCamera) |
73 | return; |
74 | |
75 | QQuick3DObjectPrivate::attachWatcher(context: this, setter: &QQuick3DXrOrigin::setCamera, newO: m_camera, oldO: newCamera); |
76 | |
77 | m_camera = newCamera; |
78 | |
79 | if (m_camera) { |
80 | // Ensure that the parent item is the XrOrigin |
81 | QQuick3DObject *camParentItem = m_camera->parentItem(); |
82 | if (camParentItem != this) { |
83 | m_camera->setParentItem(this); |
84 | if (camParentItem != nullptr) |
85 | qWarning() << "XrCamera needs to be a child of XrOrigin. Reparenting..." ; |
86 | } |
87 | |
88 | // If there's a camera, it will call this function to update the camera settings |
89 | // when its properties change. |
90 | syncCameraSettings(); |
91 | } else { |
92 | // Restore default values |
93 | resetCameraSettings(); |
94 | } |
95 | |
96 | emit cameraChanged(); |
97 | } |
98 | |
99 | QQuick3DXrEyeCamera *QQuick3DXrOrigin::eyeCamera(int index) const |
100 | { |
101 | return m_eyeCameras[index]; |
102 | } |
103 | |
104 | void QQuick3DXrOrigin::syncCameraSettings() |
105 | { |
106 | QSSG_ASSERT(m_camera != nullptr, return); |
107 | |
108 | for (auto eyeCamera : m_eyeCameras) { |
109 | eyeCamera->setClipNear(m_camera->clipNear()); |
110 | eyeCamera->setClipFar(m_camera->clipFar()); |
111 | } |
112 | } |
113 | |
114 | void QQuick3DXrOrigin::resetCameraSettings() |
115 | { |
116 | Q_ASSERT(!m_camera); |
117 | |
118 | if (QQuick3DXrView *xrView = qobject_cast<QQuick3DXrView *>(object: parentItem())) { |
119 | // Use the default clip distances from the XrManager |
120 | float nearClip, farClip; |
121 | xrView->xrManager()->getDefaultClipDistances(nearClip, farClip); |
122 | for (auto eyeCamera : m_eyeCameras) { |
123 | eyeCamera->setClipNear(nearClip); |
124 | eyeCamera->setClipFar(farClip); |
125 | } |
126 | } |
127 | } |
128 | |
129 | void QQuick3DXrOrigin::updateTrackedCamera(const QMatrix4x4 &transform) |
130 | { |
131 | if (m_camera) |
132 | QQuick3DNodePrivate::get(node: m_camera)->setLocalTransform(transform); |
133 | } |
134 | |
135 | void QQuick3DXrOrigin::updateTrackedCamera(QVector3D position, QQuaternion rotation) |
136 | { |
137 | if (m_camera) { |
138 | m_camera->setPosition(position); |
139 | m_camera->setRotation(rotation); |
140 | } |
141 | } |
142 | |
143 | QT_END_NAMESPACE |
144 | |