summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-10-12 13:22:17 +0200
committerPaul Lemire <paul.lemire@kdab.com>2015-10-14 18:52:42 +0000
commit6cf4712bda7d3453ddf728f5903374abd2f4efc9 (patch)
treed30f8d8421d30b7175d687eea91df8e697a54a88 /src
parentc8b386a57d53eb2c24f1e32f483569c56db6f362 (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.h2
-rw-r--r--src/render/backend/entity.cpp5
-rw-r--r--src/render/backend/entity_p.h2
-rw-r--r--src/render/frontend/qrenderaspect.cpp13
-rw-r--r--src/render/frontend/qrenderaspect_p.h4
-rw-r--r--src/render/geometry/qgeometryrenderer.h2
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp130
-rw-r--r--src/render/jobs/calcboundingvolumejob_p.h73
-rw-r--r--src/render/jobs/framepreparationjob.cpp16
-rw-r--r--src/render/jobs/jobs.pri6
-rw-r--r--src/render/jobs/renderviewjobutils.cpp7
-rw-r--r--src/render/jobs/updateboundingvolumejob.cpp10
-rw-r--r--src/render/jobs/updateworldtransformjob.cpp1
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);