summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorSvenn-Arne Dragly <svenn-arne.dragly@qt.io>2018-01-18 09:57:11 +0100
committerSvenn-Arne Dragly <svenn-arne.dragly@qt.io>2018-01-22 09:18:03 +0000
commita2c6dba05776a757dde58f5247f30bd3c0c66d2d (patch)
treefc1dd2f918fc89ecd5544c08eacaf1268d081d53 /tests
parent9409dd81287af75108023abbd66e49e07ba65de6 (diff)
Calculate and store real transform of camera in addition to view matrix
We used to store the viewMatrix as returned by QMatrix4x4::lookAt in the transform component of the QCamera. This was unfortunate for two reasons: 1) An arbitrary entity could not be used as a camera without changing its transform to a viewMatrix, which breaks any other use of the entity. 2) Adding entities as children to cameras lead to the wrong transformation. This made it impossible to properly add objects that should be attached to the camera, such as the hands of a character in first-person view. This commit computes the transform of the camera based on the requested position, view center and up vector. The view matrix is calculated when the matrices are updated in the RenderView. This calculation assumes that the view direction is along the entity's negative z-axis and that the up vector is along the y-axis. Change-Id: If22b29e3d38bf55fbf79e9f7baf0c922e0a48aeb Reviewed-by: Mike Krus <mike.krus@kdab.com> Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/render/qcamera/qcamera.pro12
-rw-r--r--tests/auto/render/qcamera/tst_qcamera.cpp244
-rw-r--r--tests/auto/render/render.pro3
3 files changed, 258 insertions, 1 deletions
diff --git a/tests/auto/render/qcamera/qcamera.pro b/tests/auto/render/qcamera/qcamera.pro
new file mode 100644
index 000000000..0ce2d23bc
--- /dev/null
+++ b/tests/auto/render/qcamera/qcamera.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qcamera
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qcamera.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qcamera/tst_qcamera.cpp b/tests/auto/render/qcamera/tst_qcamera.cpp
new file mode 100644
index 000000000..82a6d8b89
--- /dev/null
+++ b/tests/auto/render/qcamera/tst_qcamera.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <QObject>
+#include <QSignalSpy>
+
+#include <qbackendnodetester.h>
+
+#include <Qt3DCore/QEntity>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qaspectjobmanager_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/qtransform.h>
+
+#include <Qt3DRender/qcamera.h>
+#include <Qt3DRender/qcameralens.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/qcamera_p.h>
+#include <Qt3DRender/private/cameralens_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/transform_p.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_sceneRoot(nullptr)
+ {
+ QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), creationChanges);
+
+ Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
+ Q_ASSERT(rootEntity);
+ m_sceneRoot = rootEntity;
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ void onRegistered() { QRenderAspect::onRegistered(); }
+ void onUnregistered() { QRenderAspect::onUnregistered(); }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
+ Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
+ Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
+ Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
+
+private:
+ Render::Entity *m_sceneRoot;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+void runRequiredJobs(Qt3DRender::TestAspect *test)
+{
+ Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
+ updateWorldTransform.setRoot(test->sceneRoot());
+ updateWorldTransform.run();
+}
+
+void fuzzyCompareMatrix(const QMatrix4x4 &a, const QMatrix4x4 &b)
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ // Fuzzy comparison. qFuzzyCompare is not suitable because zero is compared to small numbers.
+ QVERIFY(qAbs(a(i, j) - b(i, j)) < 1.0e-6f);
+ }
+ }
+}
+
+} // anonymous
+
+class tst_QCamera : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QCamera camera;
+
+ // THEN
+ QCOMPARE(camera.projectionType(), Qt3DRender::QCameraLens::PerspectiveProjection);
+ QCOMPARE(camera.nearPlane(), 0.1f);
+ QCOMPARE(camera.farPlane(), 1024.0f);
+ QCOMPARE(camera.fieldOfView(), 25.0f);
+ QCOMPARE(camera.aspectRatio(), 1.0f);
+ QCOMPARE(camera.left(), -0.5f);
+ QCOMPARE(camera.right(), 0.5f);
+ QCOMPARE(camera.bottom(), -0.5f);
+ QCOMPARE(camera.top(), 0.5f);
+ QCOMPARE(camera.exposure(), 0.0f);
+ }
+
+ void checkTransformWithParent()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QEntity> root(new Qt3DCore::QEntity);
+
+ QScopedPointer<Qt3DCore::QEntity> parent(new Qt3DCore::QEntity(root.data()));
+ Qt3DCore::QTransform *parentTransform = new Qt3DCore::QTransform();
+ parentTransform->setTranslation(QVector3D(10, 9, 8));
+ parentTransform->setRotationX(10.f);
+ parentTransform->setRotationY(20.f);
+ parentTransform->setRotationZ(30.f);
+ parent->addComponent(parentTransform);
+
+ QScopedPointer<Qt3DRender::QCamera> camera(new Qt3DRender::QCamera(parent.data()));
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ runRequiredJobs(test.data());
+
+ Qt3DRender::Render::Entity *cameraEntity = test->nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Qt3DRender::Render::EntityManager>(camera->id());
+
+ // THEN
+ QVERIFY(qFuzzyCompare(*cameraEntity->worldTransform(), parentTransform->matrix()));
+ }
+
+ void checkTransformWithParentAndLookAt()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QEntity> root(new Qt3DCore::QEntity);
+
+ QScopedPointer<Qt3DCore::QEntity> parent(new Qt3DCore::QEntity(root.data()));
+ Qt3DCore::QTransform *parentTransform = new Qt3DCore::QTransform();
+ parentTransform->setRotationZ(90.f);
+ parent->addComponent(parentTransform);
+
+ QScopedPointer<Qt3DRender::QCamera> camera(new Qt3DRender::QCamera(parent.data()));
+ camera->setPosition(QVector3D(1.f, 0.f, 0.f));
+ camera->setViewCenter(QVector3D(1.f, 0.f, -1.f)); // look in -z
+ camera->setUpVector(QVector3D(0.f, 1.f, 0.f));
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ runRequiredJobs(test.data());
+
+ Qt3DRender::Render::Entity *cameraEntity = test->nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Qt3DRender::Render::EntityManager>(camera->id());
+
+ // THEN
+ QMatrix4x4 m;
+ m.translate(0.f, 1.f, 0.f); // 90 deg z-rotation + x-translation = y-translation
+ m.rotate(90.f, QVector3D(0.f, 0.f, 1.f));
+
+ const QMatrix4x4 worldTransform = *cameraEntity->worldTransform();
+ fuzzyCompareMatrix(worldTransform, m);
+
+ }
+
+ void checkTransformOfChild()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DCore::QEntity> root(new Qt3DCore::QEntity);
+
+ QScopedPointer<Qt3DCore::QEntity> parent(new Qt3DCore::QEntity(root.data()));
+ Qt3DCore::QTransform *parentTransform = new Qt3DCore::QTransform();
+ parentTransform->setTranslation(QVector3D(10, 9, 8));
+ parent->addComponent(parentTransform);
+
+ QScopedPointer<Qt3DRender::QCamera> camera(new Qt3DRender::QCamera(parent.data()));
+ camera->setPosition(QVector3D(2.f, 3.f, 4.f));
+ camera->setViewCenter(QVector3D(1.f, 3.f, 4.f)); // looking in -x = 90 deg y-rotation
+ camera->setUpVector(QVector3D(0.f, 1.f, 0.f));
+
+ // Child coordinate system:
+ // y = camera up vector = global y
+ // z = negative camera look direction = global x
+ // x = y cross z = global -z
+ QScopedPointer<Qt3DCore::QEntity> child(new Qt3DCore::QEntity(camera.data()));
+ Qt3DCore::QTransform *childTransform = new Qt3DCore::QTransform();
+ childTransform->setTranslation(QVector3D(1.f, 2.f, 3.f));
+ child->addComponent(childTransform);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ runRequiredJobs(test.data());
+
+ Qt3DRender::Render::Entity *childEntity = test->nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Qt3DRender::Render::EntityManager>(child->id());
+
+ // THEN
+ QMatrix4x4 m;
+ m.translate(10.f, 9.f, 8.f); // parent's world translation
+ m.translate(2.f, 3.f, 4.f); // camera's world translation
+ m.translate(3.f, 2.f, -1.f); // child's world translation
+ m.rotate(90.f, QVector3D(0.f, 1.f, 0.f)); // camera's rotation
+
+ fuzzyCompareMatrix(*childEntity->worldTransform(), m);
+ }
+};
+
+
+QTEST_MAIN(tst_QCamera)
+
+#include "tst_qcamera.moc"
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index 5a82ee835..3f19a9ed3 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -108,7 +108,8 @@ qtConfig(private_tests) {
qscene2d \
scene2d \
coordinatereader \
- framegraphvisitor
+ framegraphvisitor \
+ qcamera
!macos: SUBDIRS += graphicshelpergl4
}