diff options
author | Mike Krus <mike.krus@kdab.com> | 2017-01-25 08:07:42 +0000 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2017-05-23 17:31:00 +0000 |
commit | 939b9b4b7591e8a421cf048a0a84ed3e75d81d21 (patch) | |
tree | 828ee7a6862ec5c0bd24f97cb540625a2c647376 | |
parent | e27ce2bf3b76ab4ed09508f780a8601875ea2fe8 (diff) |
Add support to move the camera so that the entire model is visible
Adds QCamera::viewAll(), QCamera::viewEntity() and QCamera::viewSphere()
to move and rotate the camera so that the view center is the center
of the sphere and the sphere fits inside the viewport
Only works in perspective projection.
Introduces a job to compute the bounding sphere of the scene
excluding the camera.
Change-Id: Id9d67787ea91c354009d5358d5db63a1c9480c70
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r-- | examples/qt3d/controls/Logo.qml | 14 | ||||
-rw-r--r-- | examples/qt3d/controls/main.qml | 9 | ||||
-rw-r--r-- | src/render/backend/abstractrenderer_p.h | 1 | ||||
-rw-r--r-- | src/render/backend/cameralens.cpp | 88 | ||||
-rw-r--r-- | src/render/backend/cameralens_p.h | 7 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 5 | ||||
-rw-r--r-- | src/render/backend/renderer_p.h | 2 | ||||
-rw-r--r-- | src/render/frontend/qcamera.cpp | 82 | ||||
-rw-r--r-- | src/render/frontend/qcamera.h | 4 | ||||
-rw-r--r-- | src/render/frontend/qcameralens.cpp | 53 | ||||
-rw-r--r-- | src/render/frontend/qcameralens.h | 5 | ||||
-rw-r--r-- | src/render/frontend/qcameralens_p.h | 6 | ||||
-rw-r--r-- | src/render/jobs/computefilteredboundingvolumejob.cpp | 130 | ||||
-rw-r--r-- | src/render/jobs/computefilteredboundingvolumejob_p.h | 91 | ||||
-rw-r--r-- | src/render/jobs/jobs.pri | 2 | ||||
-rw-r--r-- | tests/auto/render/commons/testrenderer.h | 1 |
16 files changed, 493 insertions, 7 deletions
diff --git a/examples/qt3d/controls/Logo.qml b/examples/qt3d/controls/Logo.qml index a686e29bd..2eb9abd1a 100644 --- a/examples/qt3d/controls/Logo.qml +++ b/examples/qt3d/controls/Logo.qml @@ -56,6 +56,18 @@ import Qt3D.Extras 2.0 Entity { id: sceneRoot + readonly property double cameraZ: camera.position.z + + function viewAll() { + camera.viewAll() + } + function viewLogo() { + camera.viewEntity(logoEntity) + } + function setPositionZ(z) { + camera.position = Qt.vector3d( 0.0, 0.0, z ) + } + Camera { id: camera projectionType: CameraLens.PerspectiveProjection @@ -63,7 +75,7 @@ Entity { aspectRatio: 4/3 nearPlane : 0.1 farPlane : 1000.0 - position: Qt.vector3d( 0.0, 0.0, viewCenter_z.value ) + position: Qt.vector3d( 0.0, 0.0, 7.5 ) upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) } diff --git a/examples/qt3d/controls/main.qml b/examples/qt3d/controls/main.qml index 2b438ac20..5d1f9c02c 100644 --- a/examples/qt3d/controls/main.qml +++ b/examples/qt3d/controls/main.qml @@ -178,13 +178,20 @@ Item { spacing: 5 Text { text: "Camera"; font.bold: true } - Text { text: "View Center Z" } + Text { text: "View Ctr Z: " + watch.cameraZ.toFixed(2) } Slider { id: viewCenter_z Layout.fillWidth: true minimumValue: 4 maximumValue: 12 value: 7.5 + onValueChanged: watch.setPositionZ(value) + } + Button { + id: viewAll + Layout.fillWidth: true + text: "View All" + onClicked: watch.viewLogo() } } diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index f8d9850e7..2f7545454 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -139,6 +139,7 @@ public: virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0; virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0; virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0; + virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0; virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0; diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp index 5bb3ca863..ef71507eb 100644 --- a/src/render/backend/cameralens.cpp +++ b/src/render/backend/cameralens.cpp @@ -39,10 +39,14 @@ #include "cameralens_p.h" #include <Qt3DRender/qcameralens.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/qcameralens_p.h> #include <Qt3DRender/private/renderlogging_p.h> -#include <Qt3DRender/private/managers_p.h> -#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/renderer_p.h> +#include <Qt3DRender/private/entity_p.h> +#include <Qt3DRender/private/sphere_p.h> +#include <Qt3DRender/private/computefilteredboundingvolumejob_p.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qtransform.h> @@ -54,8 +58,33 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Render { + +namespace { + +class GetBoundingVolumeWithoutCameraJob : public ComputeFilteredBoundingVolumeJob +{ +public: + GetBoundingVolumeWithoutCameraJob(CameraLens *lens, + QNodeCommand::CommandId commandId) + : m_lens(lens), m_commandId(commandId) + { + } + +protected: + void finished(const Sphere &sphere) override + { + m_lens->notifySceneBoundingVolume(sphere, m_commandId); + } + +private: + CameraLens *m_lens; + QNodeCommand::CommandId m_commandId; +}; + +} // namespace + CameraLens::CameraLens() - : BackendNode() + : BackendNode(QBackendNode::ReadWrite) , m_renderAspect(nullptr) , m_exposure(0.0f) { @@ -84,6 +113,41 @@ void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &c m_exposure = data.exposure; } +void CameraLens::computeSceneBoundingVolume(QNodeId entityId, + QNodeId cameraId, + QNodeCommand::CommandId commandId) +{ + if (!m_renderer || !m_renderAspect) + return; + NodeManagers *nodeManagers = m_renderer->nodeManagers(); + + Entity *root = m_renderer->sceneRoot(); + if (!entityId.isNull()) + root = nodeManagers->renderNodesManager()->lookupResource(entityId); + if (!root) + return; + + Entity *camNode = nodeManagers->renderNodesManager()->lookupResource(cameraId); + ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, commandId)); + job->addDependency(m_renderer->expandBoundingVolumeJob()); + job->setRoot(root); + job->ignoreSubTree(camNode); + m_renderAspect->scheduleSingleShotJob(job); +} + +void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId) +{ + if (m_pendingViewAllCommand != commandId) + return; + if (sphere.radius() > 0.f) { + QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(), + sphere.radius() }; + QVariant v; + v.setValue(data); + sendCommand(QLatin1Literal("ViewAll"), v, m_pendingViewAllCommand); + } +} + void CameraLens::setProjection(const QMatrix4x4 &projection) { m_projection = projection; @@ -111,6 +175,24 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) } break; + case CommandRequested: { + QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e); + + if (command->name() == QLatin1Literal("QueryRootBoundingVolume")) { + m_pendingViewAllCommand = command->commandId(); + QVariant v = command->data(); + QNodeId id = v.value<QNodeId>(); + computeSceneBoundingVolume({}, id, command->commandId()); + } else if (command->name() == QLatin1Literal("QueryEntityBoundingVolume")) { + m_pendingViewAllCommand = command->commandId(); + QVariant v = command->data(); + QVector<QNodeId> ids = v.value<QVector<QNodeId>>(); + if (ids.size() == 2) + computeSceneBoundingVolume(ids[0], ids[1], command->commandId()); + } + } + break; + default: break; } diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h index 4d9df84e1..4bf147f48 100644 --- a/src/render/backend/cameralens_p.h +++ b/src/render/backend/cameralens_p.h @@ -52,6 +52,7 @@ // #include <Qt3DRender/private/backendnode_p.h> +#include <Qt3DCore/private/qnodecommand_p.h> #include <QMatrix4x4> #include <QRectF> @@ -62,6 +63,7 @@ namespace Qt3DRender { namespace Render { class CameraManager; +class Sphere; class CameraLensFunctor : public Qt3DCore::QBackendNodeMapper { @@ -93,12 +95,17 @@ public: inline float exposure() const { return m_exposure; } void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId); private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId, + Qt3DCore::QNodeId cameraId, + Qt3DCore::QNodeCommand::CommandId commandId); QRenderAspect *m_renderAspect; QMatrix4x4 m_projection; + Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand; float m_exposure; }; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 6cc0dba7b..b89f21522 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1467,6 +1467,11 @@ QAspectJobPtr Renderer::syncTextureLoadingJob() return m_syncTextureLoadingJob; } +QAspectJobPtr Renderer::expandBoundingVolumeJob() +{ + return m_expandBoundingVolumeJob; +} + QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const { return static_cast<Qt3DCore::QAbstractFrameAdvanceService *>(m_vsyncFrameAdvanceService.data()); diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index de0b2a59b..e311261e0 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -189,11 +189,11 @@ public: QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE; Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE; Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE; + Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE; QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const; inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; } - inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; } inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; } inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; } inline UpdateTreeEnabledJobPtr updateTreeEnabledJob() const { return m_updateTreeEnabledJob; } diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp index 38fda277f..13d689e0e 100644 --- a/src/render/frontend/qcamera.cpp +++ b/src/render/frontend/qcamera.cpp @@ -40,6 +40,8 @@ #include "qcamera.h" #include "qcamera_p.h" +#include <QtMath> + QT_BEGIN_NAMESPACE namespace Qt3DRender { @@ -199,6 +201,36 @@ QCameraPrivate::QCameraPrivate() */ /*! + * \qmlmethod void Qt3D.Render::Camera::viewAll() + * + * Rotates and moves the camera so that it's viewCenter is the center of the scene's bounding volume + * and the entire scene fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ + +/*! + * \qmlmethod void Qt3D.Render::Camera::viewEntity(Entity entity) + * + * Rotates and moves the camera so that it's viewCenter is the center of the entity's bounding volume + * and the entire entity fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ + +/*! + * \qmlmethod void Qt3D.Render::Camera::viewSphere(vector3d center, real radius) + * + * Rotates and moves the camera so that it's viewCenter is \a center + * and a sphere of \a radius fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ + +/*! * \qmlproperty enumeration Qt3D.Render::Camera::projectionType * * Holds the type of the camera projection. @@ -393,6 +425,7 @@ QCamera::QCamera(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, 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); @@ -421,6 +454,7 @@ QCamera::QCamera(QCameraPrivate &dd, Qt3DCore::QNode *parent) QObject::connect(d_func()->m_lens, SIGNAL(bottomChanged(float)), this, SIGNAL(bottomChanged(float))); 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); @@ -636,6 +670,54 @@ void QCamera::rotateAboutViewCenter(const QQuaternion& q) } /*! + * Rotates and moves the camera so that it's viewCenter is the center of the scene's bounding volume + * and the entire scene fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ +void QCamera::viewAll() +{ + Q_D(QCamera); + d->m_lens->viewAll(id()); +} + +/*! + * Rotates and moves the camera so that it's viewCenter is \a center + * and a sphere of \a radius fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ +void QCamera::viewSphere(const QVector3D ¢er, float radius) +{ + Q_D(QCamera); + if (d->m_lens->projectionType() != QCameraLens::PerspectiveProjection || radius <= 0.f) + return; + double dist = radius / std::tan(qDegreesToRadians(d->m_lens->fieldOfView()) / 2.0f); + QVector3D dir = (d->m_viewCenter - d->m_position).normalized(); + QVector3D newPos = center - (dir * dist); + setViewCenter(center); + setPosition(newPos); +} + +/*! + * Rotates and moves the camera so that it's viewCenter is the center of the entity's bounding volume + * and the entire entity fits in the view port. + * + * \note Only works if the lens is in perspective projection mode. + * \sa Qt3D.Render::Camera::projectionType + */ +void QCamera::viewEntity(Qt3DCore::QEntity *entity) +{ + if (!entity) + return; + + Q_D(QCamera); + d->m_lens->viewEntity(entity->id(), id()); +} + +/*! * Sets the camera's projection type to \a type. */ void QCamera::setProjectionType(QCameraLens::ProjectionType type) diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h index dd7c63778..5c86ea122 100644 --- a/src/render/frontend/qcamera.h +++ b/src/render/frontend/qcamera.h @@ -150,6 +150,10 @@ public Q_SLOTS: void setUpVector(const QVector3D &upVector); void setViewCenter(const QVector3D &viewCenter); + void viewAll(); + void viewSphere(const QVector3D ¢er, float radius); + void viewEntity(Qt3DCore::QEntity *entity); + Q_SIGNALS: void projectionTypeChanged(QCameraLens::ProjectionType projectionType); void nearPlaneChanged(float nearPlane); diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp index 3c6b8db68..c9be49484 100644 --- a/src/render/frontend/qcameralens.cpp +++ b/src/render/frontend/qcameralens.cpp @@ -224,6 +224,43 @@ QCameraLensPrivate::QCameraLensPrivate() { } +void QCameraLens::viewAll(Qt3DCore::QNodeId cameraId) +{ + Q_D(QCameraLens); + if (d->m_projectionType == PerspectiveProjection) { + QVariant v; + v.setValue(cameraId); + d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryRootBoundingVolume"), v); + } +} + +void QCameraLens::viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId cameraId) +{ + Q_D(QCameraLens); + if (d->m_projectionType == PerspectiveProjection) { + QVector<Qt3DCore::QNodeId> ids = {entityId, cameraId}; + QVariant v; + v.setValue(ids); + d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryEntityBoundingVolume"), v); + } +} + +void QCameraLensPrivate::processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, + const QVariant &data) +{ + Q_Q(QCameraLens); + if (m_pendingViewAllCommand != commandId) + return; + + QVector<float> boundingVolumeData = data.value< QVector<float> >(); + if (boundingVolumeData.size() != 4) + return; + QVector3D center(boundingVolumeData[0], boundingVolumeData[1], boundingVolumeData[2]); + float radius = boundingVolumeData[3]; + Q_EMIT q->viewSphere(center, radius); + m_pendingViewAllCommand = Qt3DCore::QNodeCommand::CommandId(); +} + /*! * Constructs a QCameraLens with given \a parent */ @@ -593,6 +630,22 @@ Qt3DCore::QNodeCreatedChangeBasePtr QCameraLens::createNodeCreationChange() cons return creationChange; } +void QCameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) +{ + Q_D(QCameraLens); + switch (change->type()) { + case Qt3DCore::CommandRequested: { + Qt3DCore::QNodeCommandPtr command = qSharedPointerCast<Qt3DCore::QNodeCommand>(change); + + if (command->name() == QLatin1Literal("ViewAll")) + d->processViewAllCommand(command->inReplyTo(), command->data()); + } + break; + default: + break; + } +} + } // Qt3DRender QT_END_NAMESPACE diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h index fdb0d5868..0cd22e348 100644 --- a/src/render/frontend/qcameralens.h +++ b/src/render/frontend/qcameralens.h @@ -105,6 +105,9 @@ public: float exposure() const; + void viewAll(Qt3DCore::QNodeId cameraId); + void viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId cameraId); + public Q_SLOTS: void setProjectionType(ProjectionType projectionType); void setNearPlane(float nearPlane); @@ -130,6 +133,7 @@ Q_SIGNALS: void topChanged(float top); void projectionMatrixChanged(const QMatrix4x4 &projectionMatrix); void exposureChanged(float exposure); + void viewSphere(const QVector3D ¢er, float radius); protected: explicit QCameraLens(QCameraLensPrivate &dd, QNode *parent = nullptr); @@ -137,6 +141,7 @@ protected: private: Q_DECLARE_PRIVATE(QCameraLens) Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE; }; } // Qt3DRender diff --git a/src/render/frontend/qcameralens_p.h b/src/render/frontend/qcameralens_p.h index 71759d5f8..d78579b70 100644 --- a/src/render/frontend/qcameralens_p.h +++ b/src/render/frontend/qcameralens_p.h @@ -51,7 +51,8 @@ // We mean it. // -#include <Qt3DCore/private/qcomponent_p.h> +#include <private/qcomponent_p.h> +#include <private/qnodecommand_p.h> #include "qcameralens.h" #include <Qt3DCore/qpropertyupdatedchange.h> @@ -103,6 +104,9 @@ public: float m_exposure; + Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand; + void processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, const QVariant &data); + private: inline void updatePerpectiveProjection() { diff --git a/src/render/jobs/computefilteredboundingvolumejob.cpp b/src/render/jobs/computefilteredboundingvolumejob.cpp new file mode 100644 index 000000000..d8a7b5094 --- /dev/null +++ b/src/render/jobs/computefilteredboundingvolumejob.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "computefilteredboundingvolumejob_p.h" + +#include <Qt3DRender/private/renderer_p.h> +#include <Qt3DRender/private/entity_p.h> +#include <Qt3DRender/private/renderlogging_p.h> +#include <Qt3DRender/private/sphere_p.h> +#include <Qt3DRender/private/job_common_p.h> + +#include <QThread> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +namespace { + +void expandWorldBoundingVolume(Qt3DRender::Render::Sphere *sphere, + Qt3DRender::Render::Entity *node, + Qt3DRender::Render::Entity *excludeSubTree) +{ + Qt3DRender::Render::Sphere childSphere(*node->worldBoundingVolume()); + // Go to the nodes that have the most depth + const auto children = node->children(); + for (Entity *c : children) { + if (c != excludeSubTree) + expandWorldBoundingVolume(&childSphere, c, excludeSubTree); + } + sphere->expandToContain(childSphere); +} + +} // namespace + +ComputeFilteredBoundingVolumeJob::ComputeFilteredBoundingVolumeJob() + : m_root(nullptr) + , m_ignoreSubTree(nullptr) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); +} + +void ComputeFilteredBoundingVolumeJob::setRoot(Entity *root) +{ + m_root = root; +} + +void ComputeFilteredBoundingVolumeJob::ignoreSubTree(Entity *node) +{ + m_ignoreSubTree = node; +} + +void ComputeFilteredBoundingVolumeJob::run() +{ + qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + + if (!m_root) + return; + if (!m_ignoreSubTree) { + finished(*m_root->worldBoundingVolumeWithChildren()); + return; + } + + bool isFilterChildOfRoot = false; + Entity *parent = m_ignoreSubTree->parent(); + while (parent) { + if (parent == m_root) { + isFilterChildOfRoot = true; + break; + } + parent = parent->parent(); + } + if (!isFilterChildOfRoot) { + finished(*m_root->worldBoundingVolumeWithChildren()); + return; + } + + Qt3DRender::Render::Sphere sphere; + expandWorldBoundingVolume(&sphere, m_root, m_ignoreSubTree); + finished(sphere); + + qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); +} + +void ComputeFilteredBoundingVolumeJob::finished(const Qt3DRender::Render::Sphere &sphere) +{ + Q_UNUSED(sphere); +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE diff --git a/src/render/jobs/computefilteredboundingvolumejob_p.h b/src/render/jobs/computefilteredboundingvolumejob_p.h new file mode 100644 index 000000000..d7681e604 --- /dev/null +++ b/src/render/jobs/computefilteredboundingvolumejob_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_H +#define QT3DRENDER_RENDER_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qaspectjob.h> +#include <private/qt3drender_global_p.h> + +#include <QtCore/QSharedPointer> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class Entity; +class Sphere; + +class QT3DRENDERSHARED_PRIVATE_EXPORT ComputeFilteredBoundingVolumeJob : public Qt3DCore::QAspectJob +{ +public: + ComputeFilteredBoundingVolumeJob(); + + void setRoot(Entity *root); + void ignoreSubTree(Entity *node); + void run() Q_DECL_OVERRIDE; + +protected: + virtual void finished(const Qt3DRender::Render::Sphere &sphere); + +private: + Entity *m_root; + Entity *m_ignoreSubTree; +}; + +typedef QSharedPointer<ComputeFilteredBoundingVolumeJob> ComputeFilteredBoundingVolumeJobPtr; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_H diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri index 010914f88..66c98b1c0 100644 --- a/src/render/jobs/jobs.pri +++ b/src/render/jobs/jobs.pri @@ -11,6 +11,7 @@ HEADERS += \ $$PWD/calcboundingvolumejob_p.h \ $$PWD/pickboundingvolumejob_p.h \ $$PWD/calcgeometrytrianglevolumes_p.h \ + $$PWD/computefilteredboundingvolumejob_p.h \ $$PWD/job_common_p.h \ $$PWD/filterlayerentityjob_p.h \ $$PWD/filterentitybycomponentjob_p.h \ @@ -42,6 +43,7 @@ SOURCES += \ $$PWD/calcboundingvolumejob.cpp \ $$PWD/pickboundingvolumejob.cpp \ $$PWD/calcgeometrytrianglevolumes.cpp \ + $$PWD/computefilteredboundingvolumejob.cpp \ $$PWD/filterlayerentityjob.cpp \ $$PWD/materialparametergathererjob.cpp \ $$PWD/renderviewbuilderjob.cpp \ diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h index 74f529fa0..031ca214b 100644 --- a/tests/auto/render/commons/testrenderer.h +++ b/tests/auto/render/commons/testrenderer.h @@ -60,6 +60,7 @@ public: QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE { return QVector<Qt3DCore::QAspectJobPtr>(); } Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); } Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); } + Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); } void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Qt3DRender::Render::Entity *root) Q_DECL_OVERRIDE { Q_UNUSED(factory); Q_UNUSED(root); } Qt3DRender::Render::Entity *sceneRoot() const Q_DECL_OVERRIDE { return nullptr; } Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const Q_DECL_OVERRIDE { return nullptr; } |