Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dxrcamera.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// Qt-Security score:significant reason:default
4
5
8#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
9#include <QtQuick3D/private/qquick3dutils_p.h>
10#include <QtQuick3D/private/qquick3dnode_p_p.h>
11
12#include <cmath>
13
14QT_BEGIN_NAMESPACE
15/*!
16 \qmltype XrCamera
17 \inherits Node
18 \inqmlmodule QtQuick3D.Xr
19 \brief Tracks spatial position and orientation from which the user views an XR scene.
20
21 The XrCamera is a tracked spatial node that tracks the spatial position and orientation
22 of the users's view of an XR scene.
23
24 Since this is a tracked node, its spatial properties should be considered read-only.
25 Properties specific to the XrCamera, such as the \l{clipNear}{near} and \l{clipFar}{far} clip planes, are settable.
26 When set, they override preferred values.
27
28
29 \sa XrOrigin::camera
30*/
31
32QQuick3DXrEyeCamera::QQuick3DXrEyeCamera(QQuick3DXrOrigin *parent)
33 : QQuick3DCamera(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::CustomCamera, QQuick3DContentLayer::LayerAll)), parent)
34{
35}
36
37float QQuick3DXrEyeCamera::leftTangent() const
38{
39 return m_leftTangent;
40}
41
42float QQuick3DXrEyeCamera::rightTangent() const
43{
44 return m_rightTangent;
45}
46
47float QQuick3DXrEyeCamera::upTangent() const
48{
49 return m_upTangent;
50}
51
52float QQuick3DXrEyeCamera::downTangent() const
53{
54 return m_downTangent;
55}
56
57float QQuick3DXrEyeCamera::clipNear() const
58{
59 return m_clipNear;
60}
61
62float QQuick3DXrEyeCamera::clipFar() const
63{
64 return m_clipFar;
65}
66
67void QQuick3DXrEyeCamera::setLeftTangent(float leftTangent)
68{
69 if (qFuzzyCompare(m_leftTangent, leftTangent))
70 return;
71
72 m_leftTangent = leftTangent;
73 emit leftTangentChanged(m_leftTangent);
74 markDirty(DirtyFlag::ProjectionDirty);
75}
76
77void QQuick3DXrEyeCamera::setRightTangent(float rightTangent)
78{
79 if (qFuzzyCompare(m_rightTangent, rightTangent))
80 return;
81
82 m_rightTangent = rightTangent;
83 emit rightTangentChanged(m_rightTangent);
84 markDirty(DirtyFlag::ProjectionDirty);
85}
86
87void QQuick3DXrEyeCamera::setUpTangent(float upTangent)
88{
89 if (qFuzzyCompare(m_upTangent, upTangent))
90 return;
91
92 m_upTangent = upTangent;
93 emit upTangentChanged(m_upTangent);
94 markDirty(DirtyFlag::ProjectionDirty);
95}
96
97void QQuick3DXrEyeCamera::setDownTangent(float downTangent)
98{
99 if (qFuzzyCompare(m_downTangent, downTangent))
100 return;
101
102 m_downTangent = downTangent;
103 emit downTangentChanged(m_downTangent);
104 markDirty(DirtyFlag::ProjectionDirty);
105}
106
107void QQuick3DXrEyeCamera::setClipNear(float clipNear)
108{
109 if (qFuzzyCompare(m_clipNear, clipNear))
110 return;
111
112 m_clipNear = clipNear;
113 emit clipNearChanged(m_clipNear);
114 markDirty(DirtyFlag::ProjectionDirty);
115}
116
117void QQuick3DXrEyeCamera::setClipFar(float clipFar)
118{
119 if (qFuzzyCompare(m_clipFar, clipFar))
120 return;
121
122 m_clipFar = clipFar;
123 emit clipFarChanged(m_clipFar);
124 markDirty(DirtyFlag::ProjectionDirty);
125}
126
127void QQuick3DXrEyeCamera::setProjection(const QMatrix4x4 &projection)
128{
129 m_projection = projection;
130 markDirty(DirtyFlag::ProjectionChanged);
131}
132
133QSSGRenderGraphObject *QQuick3DXrEyeCamera::updateSpatialNode(QSSGRenderGraphObject *node)
134{
135 QSSGRenderCamera *camera = static_cast<QSSGRenderCamera *>(QQuick3DCamera::updateSpatialNode(node));
136 if (camera) {
137 // Projection changed takes precedence over projection dirty
138 bool changed = false;
139 if (m_dirtyFlags & DirtyFlag::ProjectionChanged) {
140 camera->projection = m_projection;
141 qUpdateIfNeeded(camera->clipPlanes, { m_clipNear, m_clipFar });
142 m_dirtyFlags &= ~DirtyFlag::ProjectionChanged;
143 changed = true;
144 } else if (m_dirtyFlags & DirtyFlag::ProjectionDirty) {
145 maybeUpdateProjection();
146 changed |= qUpdateIfNeeded(camera->projection, m_projection);
147 qUpdateIfNeeded(camera->clipPlanes, { m_clipNear, m_clipFar });
148 m_dirtyFlags &= ~DirtyFlag::ProjectionDirty;
149 }
150
151 if (m_dirtyFlags & DirtyFlag::ClipChanged) {
152 qUpdateIfNeeded(camera->clipPlanes, { m_clipNear, m_clipFar });
153 m_dirtyFlags &= ~DirtyFlag::ClipChanged;
154 }
155
156 // Reset the dirty flag after all updates have been done
157 m_dirtyFlags = 0;
158
159 if (changed)
160 camera->markDirty(QSSGRenderCamera::DirtyFlag::CameraDirty);
161 }
162 return camera;
163}
164
165void QQuick3DXrEyeCamera::markDirty(DirtyFlag flag)
166{
167 if (m_dirtyFlags & flag)
168 return;
169
170 m_dirtyFlags |= flag;
171 update();
172}
173
174void QQuick3DXrEyeCamera::maybeUpdateProjection()
175{
176 QSSG_ASSERT(m_dirtyFlags & DirtyFlag::ProjectionDirty, return);
177
178 const float right = m_rightTangent * m_clipNear;
179 const float top = m_upTangent * m_clipNear;
180#if defined(Q_OS_VISIONOS)
181 // cp_view_get_tangents always returns positive values
182 // so we need to negate the left and down tangents
183 const float left = -m_leftTangent * m_clipNear;
184 const float bottom = -m_downTangent * m_clipNear;
185#else
186 const float left = m_leftTangent * m_clipNear;
187 const float bottom = m_downTangent * m_clipNear;
188#endif
189
190 float *m = m_projection.data();
191
192 m[0] = 2 * m_clipNear / (right - left);
193 m[4] = 0;
194 m[8] = (right + left) / (right - left);
195 m[12] = 0;
196
197 m[1] = 0;
198 m[5] = 2 * m_clipNear / (top - bottom);
199 m[9] = (top + bottom) / (top - bottom);
200 m[13] = 0;
201
202 m[2] = 0;
203 m[6] = 0;
204 m[10] = m_clipFar / (m_clipNear - m_clipFar);
205 m[14] = m_clipFar * m_clipNear / (m_clipNear - m_clipFar);
206
207
208 m[3] = 0;
209 m[7] = 0;
210 m[11] = -1;
211 m[15] = 0;
212
213 const bool isReverseZ = false; // placeholder
214 if (isReverseZ) {
215 if (std::isinf(m_clipFar)) {
216 m[10] = 0;
217 m[14] = m_clipNear;
218 } else {
219 m[10] = -m[10] - 1;
220 m[14] = -m[14];
221 }
222 } else if (std::isinf(m_clipFar)) {
223 m[10] = -1;
224 m[14] = -m_clipNear;
225 }
226}
227
228QQuick3DXrCamera::QQuick3DXrCamera(QQuick3DXrOrigin *parent)
229 : QQuick3DNode(parent)
230{
231}
232
233QQuick3DXrCamera::~QQuick3DXrCamera()
234{
235}
236
237/*!
238 \qmlproperty real QtQuick3D.Xr::XrCamera::clipNear
239 \brief The start of the distance range, with reference to the camera position, in which objects will appear.
240
241 \note Unless set explicitly, the clipNear value will be set to the device's preferred value.
242*/
243
244float QQuick3DXrCamera::clipNear() const
245{
246 return m_clipNear;
247}
248
249/*!
250 \qmlproperty real QtQuick3D.Xr::XrCamera::clipFar
251 \brief The end of the distance range, with reference to the camera position, in which objects will appear.
252
253 \note Unless set explicitly, the clipFar value will be set to the device's preferred value.
254*/
255
256float QQuick3DXrCamera::clipFar() const
257{
258 return m_clipFar;
259}
260
261void QQuick3DXrCamera::setClipNear(float clipNear)
262{
263 if (qFuzzyCompare(m_clipNear, clipNear))
264 return;
265
266 m_clipNear = clipNear;
267
268 syncCameraSettings();
269
270 emit clipNearChanged(m_clipNear);
271}
272
273void QQuick3DXrCamera::setClipFar(float clipFar)
274{
275 if (qFuzzyCompare(m_clipFar, clipFar))
276 return;
277
278 m_clipFar = clipFar;
279
280 syncCameraSettings();
281
282 emit clipFarChanged(m_clipFar);
283}
284
285void QQuick3DXrCamera::itemChange(ItemChange change, const ItemChangeData &data)
286{
287 // Sanity check (If we get a tracked item we'll do this there instead).
288 if (change == QQuick3DObject::ItemParentHasChanged) {
289 if (data.item != nullptr) {
290 if (QQuick3DXrOrigin *xrOrigin = qobject_cast<QQuick3DXrOrigin *>(data.item)) {
291 xrOrigin->setCamera(this);
292 } else {
293 qWarning() << "XrCamera must be a child of an XrOrigin!";
294 setParentItem(nullptr);
295 }
296 } else {
297 QQuick3DNode::itemChange(change, data);
298 }
299 }
300}
301
302void QQuick3DXrCamera::syncCameraSettings()
303{
304 QQuick3DXrOrigin *xrOrigin = qobject_cast<QQuick3DXrOrigin *>(parentItem());
305 if (xrOrigin && xrOrigin->camera() == this)
306 xrOrigin->syncCameraSettings();
307}
308
309QT_END_NAMESPACE