diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-10-12 13:22:17 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2015-10-14 18:52:42 +0000 |
commit | 6cf4712bda7d3453ddf728f5903374abd2f4efc9 (patch) | |
tree | d30f8d8421d30b7175d687eea91df8e697a54a88 /src | |
parent | c8b386a57d53eb2c24f1e32f483569c56db6f362 (diff) |
Resurrect bounding volumes
For BackToFront sorting to work we need to calculate a depth value based
on the entity's bounding spheres. This is currently missing as there is no
AABB from which the RenderEntity's localBoundingVolume could be
calculated.
Bring it back.
RenderEntity contains two world bounding volumes from now on: just
having one that includes the children is not ideal because in some cases
we want to know the entitys own bounding volume not including the children.
This is the case when building render commands for example.
Change-Id: I20f5bccdc3f868bcbd5faa3164f0e9995a3171ec
Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/bounds/qaxisalignedboundingbox.h | 2 | ||||
-rw-r--r-- | src/render/backend/entity.cpp | 5 | ||||
-rw-r--r-- | src/render/backend/entity_p.h | 2 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 13 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect_p.h | 4 | ||||
-rw-r--r-- | src/render/geometry/qgeometryrenderer.h | 2 | ||||
-rw-r--r-- | src/render/jobs/calcboundingvolumejob.cpp | 130 | ||||
-rw-r--r-- | src/render/jobs/calcboundingvolumejob_p.h | 73 | ||||
-rw-r--r-- | src/render/jobs/framepreparationjob.cpp | 16 | ||||
-rw-r--r-- | src/render/jobs/jobs.pri | 6 | ||||
-rw-r--r-- | src/render/jobs/renderviewjobutils.cpp | 7 | ||||
-rw-r--r-- | src/render/jobs/updateboundingvolumejob.cpp | 10 | ||||
-rw-r--r-- | src/render/jobs/updateworldtransformjob.cpp | 1 |
13 files changed, 239 insertions, 32 deletions
diff --git a/src/core/bounds/qaxisalignedboundingbox.h b/src/core/bounds/qaxisalignedboundingbox.h index bf25fada3..8ef26871b 100644 --- a/src/core/bounds/qaxisalignedboundingbox.h +++ b/src/core/bounds/qaxisalignedboundingbox.h @@ -70,6 +70,8 @@ public: m_radii = QVector3D(); } + bool isNull() const { return m_center.isNull() && m_radii.isNull(); } + void update(const QVector<QVector3D> &points); inline QVector3D center() const { return m_center; } diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp index e76eb2102..a0f8d4c98 100644 --- a/src/render/backend/entity.cpp +++ b/src/render/backend/entity.cpp @@ -67,6 +67,7 @@ Entity::Entity() , m_renderer(Q_NULLPTR) , m_localBoundingVolume(new Sphere) , m_worldBoundingVolume(new Sphere) + , m_worldBoundingVolumeWithChildren(new Sphere) { } @@ -102,10 +103,10 @@ void Entity::cleanup() } delete m_localBoundingVolume; delete m_worldBoundingVolume; + delete m_worldBoundingVolumeWithChildren; m_localBoundingVolume = Q_NULLPTR; m_worldBoundingVolume = Q_NULLPTR; - - + m_worldBoundingVolumeWithChildren = Q_NULLPTR; } void Entity::setParentHandle(HEntity parentHandle) diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h index 947dccef1..74c8e1b51 100644 --- a/src/render/backend/entity_p.h +++ b/src/render/backend/entity_p.h @@ -103,6 +103,7 @@ public: const QMatrix4x4 *worldTransform() const; Sphere *localBoundingVolume() { return m_localBoundingVolume; } Sphere *worldBoundingVolume() { return m_worldBoundingVolume; } + Sphere *worldBoundingVolumeWithChildren() { return m_worldBoundingVolumeWithChildren; } void addComponent(Qt3DCore::QComponent *component); void removeComponent(const Qt3DCore::QNodeId &nodeId); @@ -164,6 +165,7 @@ private: HMatrix m_worldTransform; Sphere *m_localBoundingVolume; Sphere *m_worldBoundingVolume; + Sphere *m_worldBoundingVolumeWithChildren; // Handles to Components Qt3DCore::QNodeId m_transformComponent; diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 3e9dffdcd..d67090ebb 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -273,7 +273,8 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) d->m_framePreparationJob.reset(new Render::FramePreparationJob(d->m_renderer->renderSceneRoot())); d->m_cleanupJob.reset(new Render::FrameCleanupJob(d->m_renderer)); d->m_worldTransformJob.reset(new Render::UpdateWorldTransformJob(d->m_renderer->renderSceneRoot())); - d->m_boundingVolumeJob.reset(new Render::UpdateBoundingVolumeJob(d->m_renderer->renderSceneRoot())); + d->m_updateBoundingVolumeJob.reset(new Render::UpdateBoundingVolumeJob(d->m_renderer->renderSceneRoot())); + d->m_calculateBoundingVolumeJob.reset(new Render::CalculateBoundingVolumeJob(d->m_renderer, d->m_renderer->renderSceneRoot())); const QVector<QNodeId> texturesPending = d->m_renderer->textureDataManager()->texturesPending(); Q_FOREACH (const QNodeId &textureId, texturesPending) { @@ -298,12 +299,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) // Create jobs to update transforms and bounding volumes // We can only update bounding volumes once all world transforms are known - d->m_boundingVolumeJob->addDependency(d->m_worldTransformJob); + d->m_updateBoundingVolumeJob->addDependency(d->m_worldTransformJob); d->m_framePreparationJob->addDependency(d->m_worldTransformJob); + // All world stuff depends on the RenderEntity's localBoundingVolume + d->m_worldTransformJob->addDependency(d->m_calculateBoundingVolumeJob); + // Add all jobs to queue + jobs.append(d->m_calculateBoundingVolumeJob); jobs.append(d->m_worldTransformJob); - jobs.append(d->m_boundingVolumeJob); + jobs.append(d->m_updateBoundingVolumeJob); jobs.append(d->m_framePreparationJob); // Traverse the current framegraph and create jobs to populate @@ -312,7 +317,7 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) // TODO: Add wrapper around ThreadWeaver::Collection for (int i = 0; i < renderBinJobs.size(); ++i) { QAspectJobPtr renderBinJob = renderBinJobs.at(i); - renderBinJob->addDependency(d->m_boundingVolumeJob); + renderBinJob->addDependency(d->m_updateBoundingVolumeJob); jobs.append(renderBinJob); d->m_cleanupJob->addDependency(renderBinJob); } diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 18b1ce91a..c4a54e017 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -52,6 +52,7 @@ #include <Qt3DRenderer/qrenderaspect.h> #include <Qt3DRenderer/private/updateboundingvolumejob_p.h> #include <Qt3DRenderer/private/updateworldtransformjob_p.h> +#include <Qt3DRenderer/private/calcboundingvolumejob_p.h> #include <Qt3DRenderer/private/framepreparationjob_p.h> #include <Qt3DRenderer/private/framecleanupjob_p.h> #include <Qt3DRenderer/private/platformsurfacefilter_p.h> @@ -86,7 +87,8 @@ class QRenderAspectPrivate : public Qt3DCore::QAbstractAspectPrivate Render::FramePreparationJobPtr m_framePreparationJob; Render::FrameCleanupJobPtr m_cleanupJob; Render::UpdateWorldTransformJobPtr m_worldTransformJob; - Render::UpdateBoundingVolumeJobPtr m_boundingVolumeJob; + Render::UpdateBoundingVolumeJobPtr m_updateBoundingVolumeJob; + Render::CalculateBoundingVolumeJobPtr m_calculateBoundingVolumeJob; }; } diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h index 31e42e2db..bb4d8a85b 100644 --- a/src/render/geometry/qgeometryrenderer.h +++ b/src/render/geometry/qgeometryrenderer.h @@ -82,7 +82,7 @@ public: }; Q_ENUM(PrimitiveType) - // how to figure out index count, bounding boxes, and all the fancy stuff that QMeshData provides for us? + // how to figure out index count and all the fancy stuff that QMeshData provides for us? // also how to figure out which attribute(s?) hold the indices? int instanceCount() const; diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp new file mode 100644 index 000000000..798de964d --- /dev/null +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "calcboundingvolumejob_p.h" + +#include <Qt3DRenderer/private/renderer_p.h> +#include <Qt3DRenderer/private/entity_p.h> +#include <Qt3DRenderer/private/renderlogging_p.h> +#include <Qt3DRenderer/private/managers_p.h> +#include <Qt3DRenderer/private/geometryrenderer_p.h> +#include <Qt3DRenderer/private/buffermanager_p.h> +#include <Qt3DRenderer/private/buffer_p.h> +#include <Qt3DRenderer/sphere.h> +#include <Qt3DCore/qaxisalignedboundingbox.h> + +#include <QtCore/qmath.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +namespace { + +void calculateLocalBoundingVolume(Renderer *renderer, Entity *node) +{ + Qt3DRender::Render::GeometryRenderer *mesh = node->renderComponent<GeometryRenderer>(); + if (mesh) { + Geometry *geom = renderer->geometryManager()->lookupResource(mesh->geometryId()); + if (geom) { + Q_FOREACH (const Qt3DCore::QNodeId &attrId, geom->attributes()) { + Attribute *attr = renderer->attributeManager()->lookupResource(attrId); + if (!attr + || attr->attributeType() != Qt3DCore::QAbstractAttribute::VertexAttribute + || !attr->isDirty() + || attr->name() != QAttribute::defaultPositionAttributeName() + || attr->dataType() != Qt3DCore::QAbstractAttribute::Float + || attr->dataSize() < 3) + continue; + + Buffer *buf = renderer->bufferManager()->lookupResource(attr->bufferId()); + // No point in continuing if the positionAttribute doesn't have a suitable buffer + if (!buf) + break; + + Qt3DCore::QAxisAlignedBoundingBox bbox; + const QByteArray buffer = buf->data(); + const char *rawBuffer = buffer.constData(); + rawBuffer += attr->byteOffset(); + const int stride = attr->byteStride() ? attr->byteStride() : sizeof(float) * attr->dataSize(); + QVector<QVector3D> vertices(attr->count()); + + // TO DO: We don't need to create a vector of QVector3D + // to build bbox used to then build a sphere, we could build the sphere + // by just looking at the vertices using more efficient algorithms (EPOS, Ritters) + for (int c = 0, vC = vertices.size(); c < vC; ++c) { + QVector3D v; + const float *fptr = reinterpret_cast<const float*>(rawBuffer); + for (uint i = 0, m = qMin(attr->dataSize(), 3U); i < m; ++i) + v[i] = fptr[i]; + vertices[c] = v; + rawBuffer += stride; + } + //Phase 1 + bbox.update(vertices); + + //Phase 2 + node->localBoundingVolume()->setCenter(bbox.center()); + node->localBoundingVolume()->setRadius(bbox.maxExtent() * 0.5f); + break; + } + } + } + + Q_FOREACH (Entity *child, node->children()) + calculateLocalBoundingVolume(renderer, child); +} + +} // anonymous + +CalculateBoundingVolumeJob::CalculateBoundingVolumeJob(Renderer *renderer, Entity *node) + : m_renderer(renderer), + m_node(node) +{ +} + +void CalculateBoundingVolumeJob::run() +{ + calculateLocalBoundingVolume(m_renderer, m_node); +} + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + diff --git a/src/render/jobs/calcboundingvolumejob_p.h b/src/render/jobs/calcboundingvolumejob_p.h new file mode 100644 index 000000000..3ab704b7b --- /dev/null +++ b/src/render/jobs/calcboundingvolumejob_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_RENDER_CALCBOUNDINGVOLUMEJOB_H +#define QT3DRENDER_RENDER_CALCBOUNDINGVOLUMEJOB_H + +#include <Qt3DCore/qaspectjob.h> + +#include <QSharedPointer> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { +namespace Render { + +class Renderer; +class Entity; + +class CalculateBoundingVolumeJob : public Qt3DCore::QAspectJob +{ +public: + CalculateBoundingVolumeJob(Renderer *renderer, Entity *node); + +protected: + void run() Q_DECL_OVERRIDE; + +private: + Renderer *m_renderer; + Entity *m_node; +}; + +typedef QSharedPointer<CalculateBoundingVolumeJob> CalculateBoundingVolumeJobPtr; + +} // namespace Render +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_RENDER_CALCBOUNDINGVOLUMEJOB_H diff --git a/src/render/jobs/framepreparationjob.cpp b/src/render/jobs/framepreparationjob.cpp index 8b98fb54d..8578cdb7f 100644 --- a/src/render/jobs/framepreparationjob.cpp +++ b/src/render/jobs/framepreparationjob.cpp @@ -62,22 +62,6 @@ void FramePreparationJob::run() void FramePreparationJob::parseNodeTree(Entity *node) { - // Initialize worldBoundingVolume if Mesh associated - Qt3DRender::Render::GeometryRenderer *mesh = Q_NULLPTR; - if ((node->localBoundingVolume()->isNull()) - && (mesh = node->renderComponent<GeometryRenderer>()) != Q_NULLPTR) { - // if (!mesh->meshDataHandle().isNull()) { - // Qt3DRender::QMeshData *meshData = mesh->meshData(); - // if (meshData != Q_NULLPTR) { - // const QAxisAlignedBoundingBox box = meshData->boundingBox(); - // node->localBoundingVolume()->setCenter(box.center()); - // const QVector3D &radii = box.radii(); - // node->localBoundingVolume()->setRadius(qMax(radii.x(), qMax(radii.y(), radii.z()))); - // } - // } - // TO DO: Make that work with the GeometryRenderer - } - // Update transform properties in ShaderData QList<ShaderData *> shadersData = node->renderComponents<ShaderData>(); Q_FOREACH (ShaderData *r, shadersData) { diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri index 2c9b93a4e..166ee8554 100644 --- a/src/render/jobs/jobs.pri +++ b/src/render/jobs/jobs.pri @@ -10,7 +10,8 @@ HEADERS += \ $$PWD/framepreparationjob_p.h \ $$PWD/loadtexturedatajob_p.h \ $$PWD/loadbufferjob_p.h \ - $$PWD/loadgeometryjob_p.h + $$PWD/loadgeometryjob_p.h \ + $$PWD/calcboundingvolumejob_p.h SOURCES += \ $$PWD/updateworldtransformjob.cpp \ @@ -22,4 +23,5 @@ SOURCES += \ $$PWD/framepreparationjob.cpp \ $$PWD/loadtexturedatajob.cpp \ $$PWD/loadbufferjob.cpp \ - $$PWD/loadgeometryjob.cpp + $$PWD/loadgeometryjob.cpp \ + $$PWD/calcboundingvolumejob.cpp diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp index 7de8e4726..9d4d52797 100644 --- a/src/render/jobs/renderviewjobutils.cpp +++ b/src/render/jobs/renderviewjobutils.cpp @@ -95,7 +95,12 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN if (lens && lens->isEnabled()) { rv->setRenderCamera(lens); rv->setViewMatrix(*camNode->worldTransform()); - rv->setEyePosition(camNode->worldBoundingVolume()->center()); + + //To get the eyePostion of the camera, we need to use the inverse of the + //camera's worldTransform matrix. + const QMatrix4x4 inverseWorldTransform = camNode->worldTransform()->inverted(); + const QVector3D eyePostion(inverseWorldTransform.column(3)); + rv->setEyePosition(eyePostion); } } break; diff --git a/src/render/jobs/updateboundingvolumejob.cpp b/src/render/jobs/updateboundingvolumejob.cpp index 3c8f47262..7ec3c110c 100644 --- a/src/render/jobs/updateboundingvolumejob.cpp +++ b/src/render/jobs/updateboundingvolumejob.cpp @@ -69,14 +69,14 @@ void expandWorldBoundingVolume(Qt3DRender::Render::Entity *node) // Initialize parent bounding volume to be equal to that of the first child Qt3DRender::Render::Entity *parentNode = currentNode->parent(); - Qt3DRender::Sphere *parentBoundingVolume = parentNode->worldBoundingVolume(); - *(parentBoundingVolume) = *(currentNode->worldBoundingVolume()); + Qt3DRender::Sphere *parentBoundingVolume = parentNode->worldBoundingVolumeWithChildren(); + *(parentBoundingVolume) = *(currentNode->worldBoundingVolumeWithChildren()); // Expand the parent bounding volume by each of remaining the siblings QVector<Entity *> siblings = parentNode->children(); const int siblingCount = siblings.count(); for (int i = 1; i < siblingCount; ++i) { - Qt3DRender::Sphere *siblingBoundingVolume = siblings.at(i)->worldBoundingVolume(); + Qt3DRender::Sphere *siblingBoundingVolume = siblings.at(i)->worldBoundingVolumeWithChildren(); parentBoundingVolume->expandToContain(*siblingBoundingVolume); } @@ -101,8 +101,8 @@ UpdateBoundingVolumeJob::UpdateBoundingVolumeJob(Entity *node) void UpdateBoundingVolumeJob::run() { - // Expand the bounding volumes of each node that has children by the - // bounding volumes of the children + // Expand worldBoundingVolumeWithChildren of each node that has children by the + // bounding volumes of the children. // TODO: Implement this using a parallel_for qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp index 736325560..ba338f676 100644 --- a/src/render/jobs/updateworldtransformjob.cpp +++ b/src/render/jobs/updateworldtransformjob.cpp @@ -59,6 +59,7 @@ void updateWorldTransformAndBounds(Qt3DRender::Render::Entity *node, const QMatr *(node->worldTransform()) = worldTransform; *(node->worldBoundingVolume()) = node->localBoundingVolume()->transformed(worldTransform); + *(node->worldBoundingVolumeWithChildren()) = *(node->worldBoundingVolume()); // expanded in UpdateBoundingVolumeJob Q_FOREACH (Qt3DRender::Render::Entity *child, node->children()) updateWorldTransformAndBounds(child, worldTransform); |