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
144
145
146
147
148
149
150
151
152
153
154
155
156
|
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QSignalSpy>
#include <QtQuick3D/private/qquick3dperspectivecamera_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
#include <QtQuick3DUtils/private/qssgutils_p.h>
#include <limits>
class tst_QQuick3DPerspectiveCamera : public QObject
{
Q_OBJECT
// Work-around to get access to updateSpatialNode
class Camera : public QQuick3DPerspectiveCamera
{
public:
using QQuick3DCamera::updateSpatialNode;
};
class NodeItem : public QQuick3DNode
{
public:
using QQuick3DNode::updateSpatialNode;
};
private slots:
void testClipAndFov();
void testLookAt();
void mapToViewport();
};
void tst_QQuick3DPerspectiveCamera::testClipAndFov()
{
Camera camera;
auto node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(nullptr));
const auto originalNode = node; // for comparisons later...
QVERIFY(node);
const float clipNear = 0.2f;
camera.setClipNear(clipNear);
node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(node));
QCOMPARE(originalNode, node);
QVERIFY(node->isDirty(QSSGRenderCamera::DirtyFlag::CameraDirty));
QCOMPARE(clipNear, node->clipPlanes.clipNear());
const float clipFar = 0.4f;
camera.setClipFar(clipFar);
node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(node));
QCOMPARE(originalNode, node);
QVERIFY(node->isDirty(QSSGRenderCamera::DirtyFlag::CameraDirty));
QCOMPARE(clipFar, node->clipPlanes.clipFar());
const float fov = 6.2f;
camera.setFieldOfView(fov);
node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(node));
QCOMPARE(originalNode, node);
QVERIFY(node->isDirty(QSSGRenderCamera::DirtyFlag::CameraDirty));
QCOMPARE(fov, node->fov.degrees()); // fov is in degrees in the front-end API.
const QQuick3DPerspectiveCamera::FieldOfViewOrientation fovOrientation
= QQuick3DPerspectiveCamera::FieldOfViewOrientation::Horizontal;
camera.setFieldOfViewOrientation(fovOrientation);
node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(node));
QCOMPARE(originalNode, node);
QVERIFY(node->isDirty(QSSGRenderCamera::DirtyFlag::CameraDirty));
QVERIFY(node->fov.orientation() == QSSGRenderCamera::FieldOfView::Orientation::Horizontal);
camera.setFieldOfViewOrientation(QQuick3DPerspectiveCamera::FieldOfViewOrientation::Vertical);
node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(node));
QVERIFY(node->fov.orientation() == QSSGRenderCamera::FieldOfView::Orientation::Vertical);
}
void tst_QQuick3DPerspectiveCamera::testLookAt()
{
Camera cam1;
Camera cam2;
NodeItem nodeItem;
nodeItem.setPosition(QVector3D(200.f, 0.f, 0.f));
cam1.setPosition(QVector3D(100.f, 0.f, 100.f));
cam2.setPosition(QVector3D(100.f, 0.f, 100.f));
auto node = static_cast<QSSGRenderNode *>(nodeItem.updateSpatialNode(nullptr));
auto camNode1 = static_cast<QSSGRenderNode *>(cam1.updateSpatialNode(nullptr));
auto camNode2 = static_cast<QSSGRenderNode *>(cam2.updateSpatialNode(nullptr));
QVERIFY(node);
QVERIFY(camNode1);
QVERIFY(camNode2);
// Verify that using lookAt method and lookAtNode property result in same rotation
cam1.setLookAtNode(&nodeItem);
cam2.lookAt(&nodeItem);
camNode1 = static_cast<QSSGRenderNode *>(cam1.updateSpatialNode(camNode1));
camNode2 = static_cast<QSSGRenderNode *>(cam2.updateSpatialNode(camNode2));
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam1.eulerRotation().y(), -45.f));
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().z()));
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam2.eulerRotation().y(), -45.f));
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().z()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode1->localTransform)), cam1.rotation()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode2->localTransform)), cam2.rotation()));
// Verify that rotation automatically changes when moving camera and using lookAtNode property
cam1.setPosition(QVector3D(300.f, 0.f, 100.f));
cam2.setPosition(QVector3D(300.f, 0.f, 100.f));
camNode1 = static_cast<QSSGRenderNode *>(cam1.updateSpatialNode(camNode1));
camNode2 = static_cast<QSSGRenderNode *>(cam2.updateSpatialNode(camNode2));
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam1.eulerRotation().y(), 45.f)); // rotation updates
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().z()));
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam2.eulerRotation().y(), -45.f)); // rotation doesn't update
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().z()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode1->localTransform)), cam1.rotation()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode2->localTransform)), cam2.rotation()));
// Verify that rotation automatically changs when moving the target node
nodeItem.setPosition(QVector3D(200.f, 0.f, 100.f));
node = static_cast<QSSGRenderNode *>(nodeItem.updateSpatialNode(node));
camNode1 = static_cast<QSSGRenderNode *>(cam1.updateSpatialNode(camNode1));
camNode2 = static_cast<QSSGRenderNode *>(cam2.updateSpatialNode(camNode2));
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam1.eulerRotation().y(), 90.f)); // rotation updates
QVERIFY(qFuzzyIsNull(cam1.eulerRotation().z()));
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().x()));
QVERIFY(qFuzzyCompare(cam2.eulerRotation().y(), -45.f)); // rotation doesn't update
QVERIFY(qFuzzyIsNull(cam2.eulerRotation().z()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode1->localTransform)), cam1.rotation()));
QVERIFY(qFuzzyCompare(QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(camNode2->localTransform)), cam2.rotation()));
}
void tst_QQuick3DPerspectiveCamera::mapToViewport()
{
Camera camera;
auto node = static_cast<QSSGRenderCamera *>(camera.updateSpatialNode(nullptr));
QVERIFY(node);
// QTBUG-100832
const float floatMax = std::numeric_limits<float>::max();
const QVector3D largeValue(-floatMax, floatMax, floatMax);
QVector3D result = camera.mapToViewport(largeValue);
QVERIFY(result.isNull());
}
QTEST_APPLESS_MAIN(tst_QQuick3DPerspectiveCamera)
#include "tst_qquick3dperspectivecamera.moc"
|