aboutsummaryrefslogtreecommitdiffstats
path: root/src/xr/quick3dxr/qquick3dxrorigin.cpp
blob: 213d4fe3a09336a5ec9f4701bde501ea1e2ebb5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include "qquick3dxrorigin_p.h"

#include "qquick3dxrview_p.h"

#include <QtQuick3D/private/qquick3dnode_p_p.h>

#include <QtQuick3DUtils/private/qssgassert_p.h>

QT_BEGIN_NAMESPACE

/*!
    \qmltype XrOrigin
    \inherits Node
    \inqmlmodule QtQuick3D.Xr
    \brief The origin location for the XrView.

    The origin determines the center of the \l{XrView::referenceSpace}{reference space}.
    Changing the position of the origin will transport the user to a different position
    in the scene.

    Most XR platforms allow the user to move physically, changing the viewpoint. This
    does not change the position of the origin. To track the position of the headset, create
    an XrCamera and assign it to the \l camera property.

    \warning Ensure you follow best practices when changing the position/rotation of
    the origin. Not doing so may cause physical discomfort, nausea, or loss of balance.
    In the worst case, this could lead to injury or even death.
*/

QQuick3DXrOrigin::QQuick3DXrOrigin(QQuick3DNode *parent)
    : QQuick3DNode(parent)
{
    // These are the "real" cameras that are used for rendering.
    QQuick3DXrEyeCamera *leftEyeCamera = new QQuick3DXrEyeCamera(this);
    leftEyeCamera->setParentItem(this);

    QQuick3DXrEyeCamera *rightEyeCamera = new QQuick3DXrEyeCamera(this);
    rightEyeCamera->setParentItem(this);

    m_eyeCameras = { leftEyeCamera, rightEyeCamera };
}

QQuick3DXrOrigin::~QQuick3DXrOrigin()
{

}

/*!
    \qmlproperty XrCamera QtQuick3D.Xr::XrOrigin::camera
    \brief Property for adding a tracked camera node.

    \default null

    Holds an XrCamera, which is a tracked spatial node that tracks the position and orientation
    of the head-mounted display in the XR environment.

    \note This property is optional.

    \sa XrCamera
*/

QQuick3DXrCamera *QQuick3DXrOrigin::camera() const
{
    return m_camera;
}

void QQuick3DXrOrigin::setCamera(QQuick3DXrCamera *newCamera)
{
    if (m_camera == newCamera)
        return;

    QQuick3DObjectPrivate::attachWatcher(this, &QQuick3DXrOrigin::setCamera, m_camera, newCamera);

    m_camera = newCamera;

    if (m_camera) {
        // Ensure that the parent item is the XrOrigin
        QQuick3DObject *camParentItem = m_camera->parentItem();
        if (camParentItem != this) {
            m_camera->setParentItem(this);
            if (camParentItem != nullptr)
                qWarning() << "XrCamera needs to be a child of XrOrigin. Reparenting...";
        }

        // If there's a camera, it will call this function to update the camera settings
        // when its properties change.
        syncCameraSettings();
    } else {
        // Restore default values
        resetCameraSettings();
    }

    emit cameraChanged();
}

QQuick3DXrEyeCamera *QQuick3DXrOrigin::eyeCamera(int index) const
{
    return m_eyeCameras[index];
}

void QQuick3DXrOrigin::syncCameraSettings()
{
    QSSG_ASSERT(m_camera != nullptr, return);

    for (auto eyeCamera : m_eyeCameras) {
        eyeCamera->setClipNear(m_camera->clipNear());
        eyeCamera->setClipFar(m_camera->clipFar());
    }
}

void QQuick3DXrOrigin::resetCameraSettings()
{
    Q_ASSERT(!m_camera);

    if (QQuick3DXrView *xrView = qobject_cast<QQuick3DXrView *>(parentItem())) {
        // Use the default clip distances from the XrManager
        float nearClip, farClip;
        xrView->xrManager()->getDefaultClipDistances(nearClip, farClip);
        for (auto eyeCamera : m_eyeCameras) {
            eyeCamera->setClipNear(nearClip);
            eyeCamera->setClipFar(farClip);
        }
    }
}

void QQuick3DXrOrigin::updateTrackedCamera(const QMatrix4x4 &transform)
{
    if (m_camera)
        QQuick3DNodePrivate::get(m_camera)->setLocalTransform(transform);
}

void QQuick3DXrOrigin::updateTrackedCamera(QVector3D position, QQuaternion rotation)
{
    if (m_camera) {
        m_camera->setPosition(position);
        m_camera->setRotation(rotation);
    }
}

QT_END_NAMESPACE