diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2018-01-22 12:37:25 +0000 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2018-01-22 12:37:25 +0000 |
commit | 2d264ae985cf0e83b55959549093aed8c19298aa (patch) | |
tree | dc6b8553c433d9fa109ff02befa82ab9c1289699 | |
parent | 2b19bde378e084331b1b7ba9aa076270492999bb (diff) | |
parent | 10d54271444d8a8de6a25cbf18fcd78f073a5a68 (diff) | |
download | qt3d-2d264ae985cf0e83b55959549093aed8c19298aa.tar.gz |
Merge branch '5.9' into 5.10
Conflicts:
src/render/frontend/qcamera.cpp
tests/auto/render/render.pro
Change-Id: I8f848a1f863d07eecb328965fbe27d74b8d442f1
-rw-r--r-- | src/render/backend/renderview.cpp | 13 | ||||
-rw-r--r-- | src/render/frontend/qcamera.cpp | 67 | ||||
-rw-r--r-- | src/render/frontend/qcamera_p.h | 8 | ||||
-rw-r--r-- | src/render/jobs/loadgeometryjob.cpp | 1 | ||||
-rw-r--r-- | tests/auto/render/qcamera/qcamera.pro | 12 | ||||
-rw-r--r-- | tests/auto/render/qcamera/tst_qcamera.cpp | 244 | ||||
-rw-r--r-- | tests/auto/render/render.pro | 3 |
7 files changed, 323 insertions, 25 deletions
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index 31de8c1c8..f488b7e44 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -732,7 +732,18 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En void RenderView::updateMatrices() { if (m_data.m_renderCameraNode && m_data.m_renderCameraLens && m_data.m_renderCameraLens->isEnabled()) { - setViewMatrix(*m_data.m_renderCameraNode->worldTransform()); + const QMatrix4x4 cameraWorld = *(m_data.m_renderCameraNode->worldTransform()); + + const QVector4D position = cameraWorld * QVector4D(0.0f, 0.0f, 0.0f, 1.0f); + // OpenGL convention is looking down -Z + const QVector4D viewDirection = cameraWorld * QVector4D(0.0f, 0.0f, -1.0f, 0.0f); + const QVector4D upVector = cameraWorld * QVector4D(0.0f, 1.0f, 0.0f, 0.0f); + + QMatrix4x4 m; + m.lookAt(position.toVector3D(), (position + viewDirection).toVector3D(), upVector.toVector3D()); + + setViewMatrix(m); + setViewProjectionMatrix(m_data.m_renderCameraLens->projection() * viewMatrix()); //To get the eyePosition of the camera, we need to use the inverse of the //camera's worldTransform matrix. diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp index 13d689e0e..73ec2c71f 100644 --- a/src/render/frontend/qcamera.cpp +++ b/src/render/frontend/qcamera.cpp @@ -59,7 +59,28 @@ QCameraPrivate::QCameraPrivate() , m_lens(new QCameraLens()) , m_transform(new Qt3DCore::QTransform()) { - updateViewMatrix(); + updateViewMatrixAndTransform(false); +} + +void QCameraPrivate::updateViewMatrixAndTransform(bool doEmit) +{ + Q_Q(QCamera); + + const QVector3D viewDirection = (m_viewCenter - m_position).normalized(); + + QMatrix4x4 transformMatrix; + transformMatrix.translate(m_position); + + // Negative viewDirection because OpenGL convention is looking down -Z + transformMatrix.rotate(QQuaternion::fromDirection(-viewDirection, m_upVector.normalized())); + + m_transform->setMatrix(transformMatrix); + + QMatrix4x4 viewMatrix; + viewMatrix.lookAt(m_position, m_viewCenter, m_upVector); + m_viewMatrix = viewMatrix; + if (doEmit) + emit q->viewMatrixChanged(); } /*! @@ -292,29 +313,35 @@ QCameraPrivate::QCameraPrivate() /*! * \qmlproperty vector3d Qt3D.Render::Camera::position - * Holds the current position of the camera. + * Holds the current position of the camera in coordinates relative to + * the parent entity. */ /*! * \qmlproperty vector3d Qt3D.Render::Camera::upVector - * Holds the current up vector of the camera. + * Holds the current up vector of the camera in coordinates relative to + * the parent entity. */ /*! * \qmlproperty vector3d Qt3D.Render::Camera::viewCenter - * Holds the current view center of the camera. + * Holds the current view center of the camera in coordinates relative to + * the parent entity. * \readonly */ /*! * \qmlproperty vector3d Qt3D.Render::Camera::viewVector - * Holds the camera's view vector. + * Holds the camera's view vector in coordinates relative to + * the parent entity. * \readonly */ /*! * \qmlproperty matrix4x4 Qt3D.Render::Camera::viewMatrix - * Holds the camera's view matrix. + * \deprecated + * Holds the camera's view matrix in coordinates relative + * to the parent entity. * \readonly */ @@ -384,27 +411,33 @@ QCameraPrivate::QCameraPrivate() /*! * \property QCamera::position - * Holds the camera's position. + * Holds the camera's position in coordinates relative to + * the parent entity. */ /*! * \property QCamera::upVector - * Holds the camera's up vector. + * Holds the camera's up vector in coordinates relative to + * the parent entity. */ /*! * \property QCamera::viewCenter - * Holds the camera's view center. + * Holds the camera's view center in coordinates relative to + * the parent entity. */ /*! * \property QCamera::viewVector - * Holds the camera's view vector. + * Holds the camera's view vector in coordinates relative to + * the parent entity. */ /*! * \property QCamera::viewMatrix - * Holds the camera's view matrix. + * \deprecated + * Holds the camera's view matrix in coordinates relative to + * the parent entity. */ /*! @@ -426,7 +459,7 @@ QCamera::QCamera(Qt3DCore::QNode *parent) QObject::connect(d_func()->m_lens, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)), this, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &))); QObject::connect(d_func()->m_lens, SIGNAL(exposureChanged(float)), this, SIGNAL(exposureChanged(float))); QObject::connect(d_func()->m_lens, &QCameraLens::viewSphere, this, &QCamera::viewSphere); - QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(viewMatrixChanged())); + addComponent(d_func()->m_lens); addComponent(d_func()->m_transform); } @@ -455,7 +488,7 @@ QCamera::QCamera(QCameraPrivate &dd, Qt3DCore::QNode *parent) QObject::connect(d_func()->m_lens, SIGNAL(topChanged(float)), this, SIGNAL(topChanged(float))); QObject::connect(d_func()->m_lens, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)), this, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &))); QObject::connect(d_func()->m_lens, &QCameraLens::viewSphere, this, &QCamera::viewSphere); - QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(viewMatrixChanged())); + addComponent(d_func()->m_lens); addComponent(d_func()->m_transform); } @@ -894,7 +927,7 @@ void QCamera::setPosition(const QVector3D &position) d->m_viewMatrixDirty = true; emit positionChanged(position); emit viewVectorChanged(d->m_cameraToCenter); - d->updateViewMatrix(); + d->updateViewMatrixAndTransform(); } } @@ -914,7 +947,7 @@ void QCamera::setUpVector(const QVector3D &upVector) d->m_upVector = upVector; d->m_viewMatrixDirty = true; emit upVectorChanged(upVector); - d->updateViewMatrix(); + d->updateViewMatrixAndTransform(); } } @@ -936,7 +969,7 @@ void QCamera::setViewCenter(const QVector3D &viewCenter) d->m_viewMatrixDirty = true; emit viewCenterChanged(viewCenter); emit viewVectorChanged(d->m_cameraToCenter); - d->updateViewMatrix(); + d->updateViewMatrixAndTransform(); } } @@ -955,7 +988,7 @@ QVector3D QCamera::viewVector() const QMatrix4x4 QCamera::viewMatrix() const { Q_D(const QCamera); - return d->m_transform->matrix(); + return d->m_viewMatrix; } } // Qt3DRender diff --git a/src/render/frontend/qcamera_p.h b/src/render/frontend/qcamera_p.h index 2ef53818c..1e8464d05 100644 --- a/src/render/frontend/qcamera_p.h +++ b/src/render/frontend/qcamera_p.h @@ -67,12 +67,7 @@ public: Q_DECLARE_PUBLIC(QCamera) - void updateViewMatrix() - { - QMatrix4x4 m; - m.lookAt(m_position, m_viewCenter, m_upVector); - m_transform->setMatrix(m); - } + void updateViewMatrixAndTransform(bool doEmit = true); QVector3D m_position; QVector3D m_viewCenter; @@ -84,6 +79,7 @@ public: // Components QCameraLens *m_lens; Qt3DCore::QTransform *m_transform; + QMatrix4x4 m_viewMatrix; }; } // namespace Qt3DRender diff --git a/src/render/jobs/loadgeometryjob.cpp b/src/render/jobs/loadgeometryjob.cpp index 106ccbd86..d28b15a7c 100644 --- a/src/render/jobs/loadgeometryjob.cpp +++ b/src/render/jobs/loadgeometryjob.cpp @@ -51,6 +51,7 @@ namespace Render { LoadGeometryJob::LoadGeometryJob(const HGeometryRenderer &handle) : QAspectJob() , m_handle(handle) + , m_nodeManagers(nullptr) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadGeometry, 0); } 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 32a7b35fc..da01dd95f 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -109,7 +109,8 @@ qtConfig(private_tests) { proximityfilter \ proximityfiltering \ qblitframebuffer \ - blitframebuffer + blitframebuffer \ + qcamera QT_FOR_CONFIG = 3dcore-private qtConfig(qt3d-extras) { |