summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2020-03-07 09:27:16 +0000
committerMike Krus <mike.krus@kdab.com>2020-04-23 10:46:06 +0100
commit60f42119fe5c341880f4576e0c9ad8d99ee277d5 (patch)
treee3a4992e501593c64ad506c13c0ddae87e9f5018
parentee476605629a74fb824d3f014deb6e6be9e40e9f (diff)
downloadqt3d-60f42119fe5c341880f4576e0c9ad8d99ee277d5.tar.gz
Pull bounding volume info from front end
When an entity has a bounding QBoundingVolume component AND that has a QGeometryView, the bounding volume can be computed by the core aspect and the results get pulled to the render backend. Otherwise, we use the old code which computes the bounding volume in the render aspect. This means we have 2 jobs to compute bounding volumes and that the core version must complete before the render aspect runs. Change-Id: I4de45e48fa0c4d40d3d5084f387abfed5ea1a2f8 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--examples/qt3d/scene3d/AnimatedEntity.qml6
-rw-r--r--examples/qt3d/scene3d/main.qml21
-rw-r--r--src/core/geometry/qgeometryview.cpp2
-rw-r--r--src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp2
-rw-r--r--src/render/frontend/qrenderaspect.cpp10
-rw-r--r--src/render/geometry/geometryrenderer.cpp18
-rw-r--r--src/render/geometry/geometryrenderer_p.h3
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp135
-rw-r--r--src/render/jobs/calcboundingvolumejob_p.h12
-rw-r--r--tests/auto/render/boundingsphere/tst_boundingsphere.cpp73
-rw-r--r--tests/auto/render/commons/testaspect.h27
-rw-r--r--tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp46
-rw-r--r--tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp2
-rw-r--r--tests/auto/render/raycastingjob/tst_raycastingjob.cpp56
14 files changed, 316 insertions, 97 deletions
diff --git a/examples/qt3d/scene3d/AnimatedEntity.qml b/examples/qt3d/scene3d/AnimatedEntity.qml
index 3e24dc785..962317a6b 100644
--- a/examples/qt3d/scene3d/AnimatedEntity.qml
+++ b/examples/qt3d/scene3d/AnimatedEntity.qml
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import Qt3D.Core 2.0
+import Qt3D.Core 2.15
import Qt3D.Render 2.15
import Qt3D.Input 2.0
import Qt3D.Extras 2.15
@@ -60,6 +60,10 @@ Entity {
id: sceneRoot
property RenderCapabilities capabilities : renderSettings.renderCapabilities
+ property bool validBounds: sphereMesh.implicitPointsValid
+ property vector3d sphereMinPt: sphereMesh.implicitMinPoint
+ property vector3d sphereMaxPt: sphereMesh.implicitMaxPoint
+
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
diff --git a/examples/qt3d/scene3d/main.qml b/examples/qt3d/scene3d/main.qml
index 6d5617ca3..f7ba24ab4 100644
--- a/examples/qt3d/scene3d/main.qml
+++ b/examples/qt3d/scene3d/main.qml
@@ -151,6 +151,27 @@ Item {
}
}
+ Rectangle {
+ radius: 10
+ color: "#aaffffff"
+ border.width: 1
+ border.color: "black"
+ width: childrenRect.width + anchors.margins
+ height: childrenRect.height + anchors.margins
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.margins: 20
+ visible: rootEntity.validBounds
+
+ Column {
+ x: parent.anchors.margins / 2
+ y: x
+
+ Text { text: "Sphere:\n Min Extent: " + rootEntity.sphereMinPt }
+ Text { text: " Max Extent: " + rootEntity.sphereMaxPt }
+ }
+ }
+
SequentialAnimation {
id: animation
diff --git a/src/core/geometry/qgeometryview.cpp b/src/core/geometry/qgeometryview.cpp
index 258448ba4..44933914a 100644
--- a/src/core/geometry/qgeometryview.cpp
+++ b/src/core/geometry/qgeometryview.cpp
@@ -273,7 +273,7 @@ bool BoundingVolumeCalculator::apply(QAttribute *positionAttribute,
const float radius = (center - maxDistantPointCenter.maxDistPt).length();
- if (center == Vector3D{} || radius < 0.f)
+ if (center == Vector3D{} && radius < 0.f)
return false;
m_radius = radius;
diff --git a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
index 8576e113b..4fa5a5fd1 100644
--- a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
+++ b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
@@ -48,6 +48,7 @@
#include <Qt3DCore/qbuffer.h>
#include <Qt3DCore/qgeometry.h>
#include <Qt3DCore/qgeometryview.h>
+#include <Qt3DCore/qboundingvolume.h>
#include <QtCore/qvariantanimation.h>
#include <Qt3DQuick/private/quick3dnodev9_p.h>
@@ -87,6 +88,7 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DCore::Quick::Quick3DBuffer>(uri, 2, 0, "Buffer");
Qt3DCore::Quick::registerExtendedType<Qt3DCore::QGeometry, Qt3DCore::Quick::Quick3DGeometry>("QGeometry", "Qt3D.Core/Geometry", uri, 2, 0, "Geometry");
qmlRegisterType<Qt3DCore::QGeometryView>(uri, 2, 16, "GeometryView");
+ qmlRegisterType<Qt3DCore::QBoundingVolume>(uri, 2, 16, "BoundingVolume");
qmlRegisterType<Qt3DCore::Quick::QQuaternionAnimation>(uri, 2, 0, "QuaternionAnimation");
qRegisterAnimationInterpolator<QQuaternion>(Qt3DCore::Quick::q_quaternionInterpolator);
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index 202012194..dff7f3640 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -95,6 +95,7 @@
#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qjoint.h>
#include <Qt3DCore/qskeletonloader.h>
+#include <Qt3DCore/qcoreaspect.h>
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/cameraselectornode_p.h>
@@ -297,6 +298,8 @@ void QRenderAspectPrivate::createNodeManagers()
m_updateEntityLayersJob->setManager(m_nodeManagers);
m_pickBoundingVolumeJob->setManagers(m_nodeManagers);
m_rayCastingJob->setManagers(m_nodeManagers);
+
+ m_calculateBoundingVolumeJob->setFrontEndNodeManager(m_aspectManager);
}
void QRenderAspectPrivate::onEngineStartup()
@@ -316,6 +319,13 @@ void QRenderAspectPrivate::onEngineStartup()
// Ensures all skeletons are loaded before we try to update them
m_updateSkinningPaletteJob->addDependency(m_syncLoadingJobs);
+
+ // make sure bv job in core aspect runs before the one in render aspect
+ if (m_aspectManager) {
+ auto *coreAspect = qobject_cast<Qt3DCore::QCoreAspect *>(m_aspectManager->aspect(&Qt3DCore::QCoreAspect::staticMetaObject));
+ Q_ASSERT(coreAspect);
+ m_calculateBoundingVolumeJob->addDependency(coreAspect->calculateBoundingVolumeJob());
+ }
}
/*! \internal */
diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp
index 5a4bdcd9c..d314e87ce 100644
--- a/src/render/geometry/geometryrenderer.cpp
+++ b/src/render/geometry/geometryrenderer.cpp
@@ -92,8 +92,6 @@ void GeometryRenderer::cleanup()
m_geometryId = Qt3DCore::QNodeId();
m_dirty = false;
m_geometryFactory.reset();
- qDeleteAll(m_triangleVolumes);
- m_triangleVolumes.clear();
}
void GeometryRenderer::setManager(GeometryRendererManager *manager)
@@ -135,8 +133,12 @@ void GeometryRenderer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime)
};
if (view) {
+ m_dirty |= !m_hasView;
+ m_hasView = true;
propertyUpdater(view);
} else {
+ m_dirty |= m_hasView;
+ m_hasView = false;
propertyUpdater(node);
const QGeometryRendererPrivate *dnode = static_cast<const QGeometryRendererPrivate *>(QNodePrivate::get(frontEnd));
@@ -210,18 +212,6 @@ void GeometryRenderer::unsetDirty()
m_dirty = false;
}
-
-void GeometryRenderer::setTriangleVolumes(const QVector<RayCasting::QBoundingVolume *> &volumes)
-{
- qDeleteAll(m_triangleVolumes);
- m_triangleVolumes = volumes;
-}
-
-QVector<RayCasting::QBoundingVolume *> GeometryRenderer::triangleData() const
-{
- return m_triangleVolumes;
-}
-
GeometryRendererFunctor::GeometryRendererFunctor(AbstractRenderer *renderer, GeometryRendererManager *manager)
: m_manager(manager)
, m_renderer(renderer)
diff --git a/src/render/geometry/geometryrenderer_p.h b/src/render/geometry/geometryrenderer_p.h
index 87a289f7d..36ba08acd 100644
--- a/src/render/geometry/geometryrenderer_p.h
+++ b/src/render/geometry/geometryrenderer_p.h
@@ -98,6 +98,7 @@ public:
inline bool isDirty() const { return m_dirty; }
inline Qt3DCore::QGeometryFactoryPtr geometryFactory() const { return m_geometryFactory; }
void unsetDirty();
+ bool hasView() const { return m_hasView; }
// Build triangle data Job thread
void setTriangleVolumes(const QVector<RayCasting::QBoundingVolume *> &volumes);
@@ -117,9 +118,9 @@ private:
bool m_primitiveRestartEnabled;
QGeometryRenderer::PrimitiveType m_primitiveType;
bool m_dirty;
+ bool m_hasView;
Qt3DCore::QGeometryFactoryPtr m_geometryFactory;
GeometryRendererManager *m_manager;
- QVector<RayCasting::QBoundingVolume *> m_triangleVolumes;
};
class GeometryRendererFunctor : public Qt3DCore::QBackendNodeMapper
diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp
index dc95151c4..b7daddbcb 100644
--- a/src/render/jobs/calcboundingvolumejob.cpp
+++ b/src/render/jobs/calcboundingvolumejob.cpp
@@ -40,10 +40,14 @@
#include "calcboundingvolumejob_p.h"
+#include <Qt3DCore/qboundingvolume.h>
+#include <Qt3DCore/qabstractfrontendnodemanager.h>
+#include <Qt3DCore/private/qgeometry_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/qgeometryrenderer_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
@@ -52,8 +56,6 @@
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/buffervisitor_p.h>
#include <Qt3DRender/private/entityvisitor_p.h>
-#include <Qt3DCore/private/qgeometry_p.h>
-#include <Qt3DCore/private/qaspectmanager_p.h>
#include <QtCore/qmath.h>
#if QT_CONFIG(concurrent)
@@ -220,34 +222,39 @@ private:
struct BoundingVolumeComputeData {
Entity *entity = nullptr;
+ GeometryRenderer *renderer = nullptr;
Geometry *geometry = nullptr;
Attribute *positionAttribute = nullptr;
Attribute *indexAttribute = nullptr;
- bool primitiveRestartEnabled = false;
- int primitiveRestartIndex = -1;
- int vertexCount = 0;
+ int vertexCount = -1;
- bool valid() const { return entity != nullptr; }
+ bool valid() const { return vertexCount >= 0; }
};
BoundingVolumeComputeData findBoundingVolumeComputeData(NodeManagers *manager, Entity *node)
{
- GeometryRenderer *gRenderer = node->renderComponent<GeometryRenderer>();
+ BoundingVolumeComputeData res;
+ res.entity = node;
+
+ res.renderer = node->renderComponent<GeometryRenderer>();
+ if (!res.renderer || res.renderer->primitiveType() == QGeometryRenderer::Patches)
+ return res;
+
GeometryManager *geometryManager = manager->geometryManager();
- if (!gRenderer || gRenderer->primitiveType() == QGeometryRenderer::Patches)
- return {};
+ res.geometry = geometryManager->lookupResource(res.renderer->geometryId());
+ if (!res.geometry)
+ return res;
- Geometry *geom = geometryManager->lookupResource(gRenderer->geometryId());
- if (!geom)
- return {};
+ if (res.renderer->hasView())
+ return res;
- int drawVertexCount = gRenderer->vertexCount(); // may be 0, gets changed below if so
+ int drawVertexCount = res.renderer->vertexCount(); // may be 0, gets changed below if so
- Qt3DRender::Render::Attribute *positionAttribute = manager->lookupResource<Attribute, AttributeManager>(geom->boundingPositionAttribute());
+ Qt3DRender::Render::Attribute *positionAttribute = manager->lookupResource<Attribute, AttributeManager>(res.geometry->boundingPositionAttribute());
// Use the default position attribute if attribute is null
if (!positionAttribute) {
- const auto attrIds = geom->attributes();
+ const auto attrIds = res.geometry->attributes();
for (const Qt3DCore::QNodeId &attrId : attrIds) {
positionAttribute = manager->lookupResource<Attribute, AttributeManager>(attrId);
if (positionAttribute &&
@@ -261,20 +268,20 @@ BoundingVolumeComputeData findBoundingVolumeComputeData(NodeManagers *manager, E
|| positionAttribute->vertexBaseType() != QAttribute::Float
|| positionAttribute->vertexSize() < 3) {
qWarning("findBoundingVolumeComputeData: Position attribute not suited for bounding volume computation");
- return {};
+ return res;
}
Buffer *buf = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
// No point in continuing if the positionAttribute doesn't have a suitable buffer
if (!buf) {
qWarning("findBoundingVolumeComputeData: Position attribute not referencing a valid buffer");
- return {};
+ return res;
}
// Check if there is an index attribute.
Qt3DRender::Render::Attribute *indexAttribute = nullptr;
Buffer *indexBuf = nullptr;
- const QVector<Qt3DCore::QNodeId> attributes = geom->attributes();
+ const QVector<Qt3DCore::QNodeId> attributes = res.geometry->attributes();
for (Qt3DCore::QNodeId attrNodeId : attributes) {
Qt3DRender::Render::Attribute *attr = manager->lookupResource<Attribute, AttributeManager>(attrNodeId);
@@ -296,7 +303,7 @@ BoundingVolumeComputeData findBoundingVolumeComputeData(NodeManagers *manager, E
std::end(validIndexTypes),
indexAttribute->vertexBaseType()) == std::end(validIndexTypes)) {
qWarning() << "findBoundingVolumeComputeData: Unsupported index attribute type" << indexAttribute->name() << indexAttribute->vertexBaseType();
- return {};
+ return res;
}
break;
@@ -314,17 +321,16 @@ BoundingVolumeComputeData findBoundingVolumeComputeData(NodeManagers *manager, E
if (buf->isDirty()
|| node->isBoundingVolumeDirty()
|| positionAttribute->isDirty()
- || geom->isDirty()
- || gRenderer->isDirty()
+ || res.geometry->isDirty()
+ || res.renderer->isDirty()
|| (indexAttribute && indexAttribute->isDirty())
|| (indexBuf && indexBuf->isDirty())) {
- return {
- node, geom, positionAttribute, indexAttribute,
- gRenderer->primitiveRestartEnabled(), gRenderer->restartIndexValue(), drawVertexCount
- };
+ res.vertexCount = drawVertexCount;
+ res.positionAttribute = positionAttribute;
+ res.indexAttribute = indexAttribute;
}
- return {};
+ return res;
}
QVector<Geometry *> calculateLocalBoundingVolume(NodeManagers *manager, const BoundingVolumeComputeData &data)
@@ -336,7 +342,7 @@ QVector<Geometry *> calculateLocalBoundingVolume(NodeManagers *manager, const Bo
BoundingVolumeCalculator reader(manager);
if (reader.apply(data.positionAttribute, data.indexAttribute, data.vertexCount,
- data.primitiveRestartEnabled, data.primitiveRestartIndex)) {
+ data.renderer->primitiveRestartEnabled(), data.renderer->restartIndexValue())) {
data.entity->localBoundingVolume()->setCenter(reader.result().center());
data.entity->localBoundingVolume()->setRadius(reader.result().radius());
data.entity->unsetBoundingVolumeDirty();
@@ -383,49 +389,56 @@ public:
if (!entity->isTreeEnabled())
return Prune;
auto data = findBoundingVolumeComputeData(m_manager, entity);
- if (data.valid())
+
+ if (data.valid()) {
+ // only valid if front end is a QGeometryRenderer without a view. All other cases handled by core aspect
m_entities.push_back(data);
+ } else {
+ if (!data.renderer || data.renderer->primitiveType() == QGeometryRenderer::Patches
+ || !data.renderer->hasView()) // should have been handled above
+ return Continue;
+
+ // renderer has a view, we can pull the data from the front end
+ QBoundingVolume *frontEndBV = qobject_cast<QBoundingVolume *>(m_frontEndNodeManager->lookupNode(data.renderer->peerId()));
+ if (!frontEndBV)
+ return Continue;
+ auto dFrontEndBV = QGeometryRendererPrivate::get(frontEndBV);
+
+ // copy data to the entity
+ entity->localBoundingVolume()->setCenter(Vector3D(dFrontEndBV->m_implicitCenter));
+ entity->localBoundingVolume()->setRadius(dFrontEndBV->m_implicitRadius);
+ entity->unsetBoundingVolumeDirty();
+ // copy the data to the geometry
+ data.geometry->updateExtent(dFrontEndBV->m_implicitMinPoint, dFrontEndBV->m_implicitMaxPoint);
+ }
+
return Continue;
}
+ NodeManagers *m_nodeNanager;
+ Qt3DCore::QAbstractFrontEndNodeManager *m_frontEndNodeManager = nullptr;
std::vector<BoundingVolumeComputeData> m_entities;
};
} // anonymous
-class CalculateBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate
-{
-public:
- CalculateBoundingVolumeJobPrivate() { }
- ~CalculateBoundingVolumeJobPrivate() override { }
-
- void postFrame(Qt3DCore::QAspectManager *manager) override
- {
- for (Geometry *backend : qAsConst(m_updatedGeometries)) {
- Qt3DCore::QGeometry *node = qobject_cast<Qt3DCore::QGeometry *>(manager->lookupNode(backend->peerId()));
- if (!node)
- continue;
- Qt3DCore::QGeometryPrivate *dNode = static_cast<Qt3DCore::QGeometryPrivate *>(Qt3DCore::QNodePrivate::get(node));
- dNode->setExtent(backend->min(), backend->max());
- }
-
- m_updatedGeometries.clear();
- }
-
- QVector<Geometry *> m_updatedGeometries;
-};
CalculateBoundingVolumeJob::CalculateBoundingVolumeJob()
- : Qt3DCore::QAspectJob(*new CalculateBoundingVolumeJobPrivate())
+ : Qt3DCore::QAspectJob()
, m_manager(nullptr)
, m_node(nullptr)
+ , m_frontEndNodeManager(nullptr)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0)
}
void CalculateBoundingVolumeJob::run()
{
+ Q_ASSERT(m_frontEndNodeManager);
+
DirtyEntityAccumulator accumulator(m_manager);
+ accumulator.m_frontEndNodeManager = m_frontEndNodeManager;
+ accumulator.m_nodeNanager = m_manager;
accumulator.apply(m_node);
std::vector<BoundingVolumeComputeData> entities = std::move(accumulator.m_entities);
@@ -446,8 +459,21 @@ void CalculateBoundingVolumeJob::run()
updatedGeometries += calculateLocalBoundingVolume(m_manager, data);
}
- Q_D(CalculateBoundingVolumeJob);
- d->m_updatedGeometries = std::move(updatedGeometries);
+ m_updatedGeometries = std::move(updatedGeometries);
+}
+
+void CalculateBoundingVolumeJob::postFrame(QAspectEngine *aspectEngine)
+{
+ Q_UNUSED(aspectEngine)
+ for (Geometry *backend : qAsConst(m_updatedGeometries)) {
+ Qt3DCore::QGeometry *node = qobject_cast<Qt3DCore::QGeometry *>(m_frontEndNodeManager->lookupNode(backend->peerId()));
+ if (!node)
+ continue;
+ Qt3DCore::QGeometryPrivate *dNode = static_cast<Qt3DCore::QGeometryPrivate *>(Qt3DCore::QNodePrivate::get(node));
+ dNode->setExtent(backend->min(), backend->max());
+ }
+
+ m_updatedGeometries.clear();
}
void CalculateBoundingVolumeJob::setRoot(Entity *node)
@@ -460,6 +486,11 @@ void CalculateBoundingVolumeJob::setManagers(NodeManagers *manager)
m_manager = manager;
}
+void CalculateBoundingVolumeJob::setFrontEndNodeManager(Qt3DCore::QAbstractFrontEndNodeManager *manager)
+{
+ m_frontEndNodeManager = manager;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/jobs/calcboundingvolumejob_p.h b/src/render/jobs/calcboundingvolumejob_p.h
index 3f7b8c09c..11392dc0b 100644
--- a/src/render/jobs/calcboundingvolumejob_p.h
+++ b/src/render/jobs/calcboundingvolumejob_p.h
@@ -59,12 +59,16 @@
QT_BEGIN_NAMESPACE
+namespace Qt3DCore {
+class QAbstractFrontEndNodeManager;
+}
+
namespace Qt3DRender {
namespace Render {
class NodeManagers;
class Entity;
-class CalculateBoundingVolumeJobPrivate;
+class Geometry;
class Q_3DRENDERSHARED_PRIVATE_EXPORT CalculateBoundingVolumeJob : public Qt3DCore::QAspectJob
{
@@ -73,12 +77,16 @@ public:
void setRoot(Entity *node);
void setManagers(NodeManagers *manager);
+ void setFrontEndNodeManager(Qt3DCore::QAbstractFrontEndNodeManager *manager);
void run() override;
+ void postFrame(Qt3DCore::QAspectEngine *aspectEngine) override;
+
private:
NodeManagers *m_manager;
Entity *m_node;
- Q_DECLARE_PRIVATE(CalculateBoundingVolumeJob)
+ Qt3DCore::QAbstractFrontEndNodeManager *m_frontEndNodeManager;
+ QVector<Geometry *> m_updatedGeometries;
};
typedef QSharedPointer<CalculateBoundingVolumeJob> CalculateBoundingVolumeJobPtr;
diff --git a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
index 7a05addcd..6fbdee807 100644
--- a/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
+++ b/tests/auto/render/boundingsphere/tst_boundingsphere.cpp
@@ -36,6 +36,7 @@
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodevisitor_p.h>
+#include <Qt3DCore/private/calcboundingvolumejob_p.h>
#include <QtQuick/qquickwindow.h>
#include <Qt3DRender/QCamera>
@@ -103,7 +104,7 @@ QVector<Qt3DCore::NodeTreeChange> nodeTreeChangesForNodes(const QVector<Qt3DCore
return nodeTreeChanges;
}
-class TestAspect : public Qt3DRender::QRenderAspect
+class TestAspect : public Qt3DRender::QRenderAspect, public Qt3DCore::QAbstractFrontEndNodeManager
{
public:
TestAspect(Qt3DCore::QNode *root)
@@ -111,10 +112,11 @@ public:
, m_sceneRoot(nullptr)
{
QRenderAspect::onRegistered();
+ m_root = qobject_cast<Qt3DCore::QEntity *>(root);
const QVector<Qt3DCore::QNode *> nodes = getNodesForCreation(root);
const QVector<Qt3DCore::NodeTreeChange> nodeTreeChanges = nodeTreeChangesForNodes(nodes);
- d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), nodeTreeChanges);
+ d_func()->setRootAndCreateNodes(m_root, nodeTreeChanges);
Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
@@ -126,17 +128,42 @@ public:
QRenderAspect::onUnregistered();
}
- void onRegistered() { QRenderAspect::onRegistered(); }
- void onUnregistered() { QRenderAspect::onUnregistered(); }
+ void onRegistered() override { QRenderAspect::onRegistered(); }
+ void onUnregistered() override { 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(); }
+ Qt3DCore::QEntity *root() const { return m_root; }
Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
Qt3DRender::Render::AbstractRenderer *renderer() const { return d_func()->m_renderer; }
+ void registerNode(Qt3DCore::QNode *node) { m_frontEndNodes.insert(node->id(), node); }
+ void registerTree(Qt3DCore::QEntity *root) {
+ using namespace Qt3DCore;
+ QNodeVisitor visitor;
+ visitor.traverse(root, [](QNode *) {}, [this](QEntity *entity) {
+ registerNode(entity);
+ const auto &components = entity->components();
+ for (const auto &c : components)
+ registerNode(c);
+ });
+ }
+ Qt3DCore::QNode *lookupNode(Qt3DCore::QNodeId id) const override { return m_frontEndNodes.value(id, nullptr); }
+ QVector<Qt3DCore::QNode *> lookupNodes(const QVector<Qt3DCore::QNodeId> &ids) const override {
+ QVector<Qt3DCore::QNode *> res;
+ for (const auto &id: ids) {
+ auto node = m_frontEndNodes.value(id, nullptr);
+ if (node)
+ res.push_back(node);
+ }
+ return res;
+ }
+
private:
+ Qt3DCore::QEntity *m_root;
Render::Entity *m_sceneRoot;
+ QHash<Qt3DCore::QNodeId, Qt3DCore::QNode *> m_frontEndNodes;
};
} // namespace Qt3DRender
@@ -152,10 +179,16 @@ void runRequiredJobs(Qt3DRender::TestAspect *test)
updateWorldTransform.setManagers(test->nodeManagers());
updateWorldTransform.run();
- Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
- calcBVolume.setManagers(test->nodeManagers());
- calcBVolume.setRoot(test->sceneRoot());
- calcBVolume.run();
+ Qt3DCore::CalculateBoundingVolumeJob calcCBVolume;
+ calcCBVolume.setRoot(test->root());
+ calcCBVolume.run();
+ calcCBVolume.postFrame(nullptr);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcRBVolume;
+ calcRBVolume.setManagers(test->nodeManagers());
+ calcRBVolume.setFrontEndNodeManager(test);
+ calcRBVolume.setRoot(test->sceneRoot());
+ calcRBVolume.run();
Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
@@ -215,7 +248,7 @@ private Q_SLOTS:
auto copiedSphere = firstValidSphere;
firstValidSphere.expandToContain(defaultSphere);
QVERIFY(firstValidSphere.center() == copiedSphere.center());
- QVERIFY(firstValidSphere.radius() == copiedSphere.radius());
+ QCOMPARE(firstValidSphere.radius(), copiedSphere.radius());
QVERIFY(!firstValidSphere.isNull());
}
@@ -224,7 +257,7 @@ private Q_SLOTS:
auto defaultSphere = Qt3DRender::Render::Sphere();
defaultSphere.expandToContain(firstValidSphere);
QVERIFY(defaultSphere.center() == firstValidSphere.center());
- QVERIFY(defaultSphere.radius() == firstValidSphere.radius());
+ QCOMPARE(defaultSphere.radius(), firstValidSphere.radius());
QVERIFY(!defaultSphere.isNull());
}
@@ -336,6 +369,7 @@ private Q_SLOTS:
QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
// Runs Required jobs
+ test->registerTree(qobject_cast<Qt3DCore::QEntity *>(root.data()));
runRequiredJobs(test.data());
// THEN
@@ -476,10 +510,18 @@ private Q_SLOTS:
entityBackend->setRenderer(test->renderer());
simulateInitializationSync(entity.data(), entityBackend);
- Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
- calcBVolume.setManagers(test->nodeManagers());
- calcBVolume.setRoot(test->sceneRoot());
- calcBVolume.run();
+ test->registerTree(entity.data());
+
+ Qt3DCore::CalculateBoundingVolumeJob calcCBVolume;
+ calcCBVolume.setRoot(test->root());
+ calcCBVolume.run();
+ calcCBVolume.postFrame(nullptr);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcRBVolume;
+ calcRBVolume.setManagers(test->nodeManagers());
+ calcRBVolume.setRoot(test->sceneRoot());
+ calcRBVolume.setFrontEndNodeManager(test.data());
+ calcRBVolume.run();
Vector3D center = entityBackend->localBoundingVolume()->center();
float radius = entityBackend->localBoundingVolume()->radius();
@@ -566,7 +608,10 @@ private Q_SLOTS:
entityBackend->setRenderer(test->renderer());
simulateInitializationSync(entity.data(), entityBackend);
+ test->registerTree(entity.data());
+
Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
+ calcBVolume.setFrontEndNodeManager(test.data());
calcBVolume.setManagers(test->nodeManagers());
calcBVolume.setRoot(test->sceneRoot());
calcBVolume.run();
diff --git a/tests/auto/render/commons/testaspect.h b/tests/auto/render/commons/testaspect.h
index dfbe78fbd..22d0a7172 100644
--- a/tests/auto/render/commons/testaspect.h
+++ b/tests/auto/render/commons/testaspect.h
@@ -41,13 +41,15 @@
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/private/abstractrenderer_p.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
+#include <Qt3DCore/private/qnodevisitor_p.h>
+#include <Qt3DCore/qabstractfrontendnodemanager.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class TestAspect : public Qt3DRender::QRenderAspect
+class TestAspect : public Qt3DRender::QRenderAspect, public Qt3DCore::QAbstractFrontEndNodeManager
{
public:
TestAspect(Qt3DCore::QNode *root);
@@ -60,8 +62,31 @@ public:
void onRegistered();
void onUnregistered();
+ void registerNode(Qt3DCore::QNode *node) { m_frontEndNodes.insert(node->id(), node); }
+ void registerTree(Qt3DCore::QEntity *root) {
+ using namespace Qt3DCore;
+ QNodeVisitor visitor;
+ visitor.traverse(root, [](QNode *) {}, [this](QEntity *entity) {
+ registerNode(entity);
+ const auto &components = entity->components();
+ for (const auto &c : components)
+ registerNode(c);
+ });
+ }
+ Qt3DCore::QNode *lookupNode(Qt3DCore::QNodeId id) const override { return m_frontEndNodes.value(id, nullptr); }
+ QVector<Qt3DCore::QNode *> lookupNodes(const QVector<Qt3DCore::QNodeId> &ids) const override {
+ QVector<Qt3DCore::QNode *> res;
+ for (const auto &id: ids) {
+ auto node = m_frontEndNodes.value(id, nullptr);
+ if (node)
+ res.push_back(node);
+ }
+ return res;
+ }
+
private:
QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager;
+ QHash<Qt3DCore::QNodeId, Qt3DCore::QNode *> m_frontEndNodes;
};
} // Qt3DRender
diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
index cd984cfac..fb61e4105 100644
--- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
+++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
@@ -32,12 +32,14 @@
#include <QtTest/QTest>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/qabstractfrontendnodemanager.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodevisitor_p.h>
#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/private/qaspectengine_p.h>
#include <Qt3DCore/private/qaspectjob_p.h>
+#include <Qt3DCore/private/calcboundingvolumejob_p.h>
#include <QtQuick/qquickwindow.h>
#include <Qt3DRender/QCamera>
@@ -112,7 +114,7 @@ QVector<Qt3DCore::NodeTreeChange> nodeTreeChangesForNodes(const QVector<Qt3DCore
return nodeTreeChanges;
}
-class TestAspect : public Qt3DRender::QRenderAspect
+class TestAspect : public Qt3DRender::QRenderAspect, public Qt3DCore::QAbstractFrontEndNodeManager
{
public:
TestAspect(Qt3DCore::QNode *root)
@@ -124,6 +126,7 @@ public:
Q_ASSERT(d_func()->m_aspectManager);
// do what QAspectEngine::setRootEntity does since we don't want to enter the simulation loop
+ m_root = qobject_cast<Qt3DCore::QEntity *>(root);
Qt3DCore::QEntityPtr proot(qobject_cast<Qt3DCore::QEntity *>(root), [](Qt3DCore::QEntity *) { });
Qt3DCore::QAspectEnginePrivate *aed = Qt3DCore::QAspectEnginePrivate::get(m_engine);
aed->m_root = proot;
@@ -135,6 +138,8 @@ public:
Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
m_sceneRoot = rootEntity;
+
+ registerTree(m_root);
}
~TestAspect()
@@ -158,12 +163,37 @@ public:
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(); }
+ Qt3DCore::QEntity *root() const { return m_root; }
Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
Qt3DCore::QAspectManager *aspectManager() const { return d_func()->m_aspectManager; }
Qt3DCore::QChangeArbiter *arbiter() const { return d_func()->m_arbiter; }
+
+ void registerNode(Qt3DCore::QNode *node) { m_frontEndNodes.insert(node->id(), node); }
+ void registerTree(Qt3DCore::QEntity *root) {
+ using namespace Qt3DCore;
+ QNodeVisitor visitor;
+ visitor.traverse(root, [](QNode *) {}, [this](QEntity *entity) {
+ registerNode(entity);
+ const auto &components = entity->components();
+ for (const auto &c : components)
+ registerNode(c);
+ });
+ }
+ Qt3DCore::QNode *lookupNode(Qt3DCore::QNodeId id) const override { return m_frontEndNodes.value(id, nullptr); }
+ QVector<Qt3DCore::QNode *> lookupNodes(const QVector<Qt3DCore::QNodeId> &ids) const override {
+ QVector<Qt3DCore::QNode *> res;
+ for (const auto &id: ids) {
+ auto node = m_frontEndNodes.value(id, nullptr);
+ if (node)
+ res.push_back(node);
+ }
+ return res;
+ }
private:
Qt3DCore::QAspectEngine *m_engine;
+ Qt3DCore::QEntity *m_root;
Render::Entity *m_sceneRoot;
+ QHash<Qt3DCore::QNodeId, Qt3DCore::QNode *> m_frontEndNodes;
};
} // namespace Qt3DRender
@@ -179,10 +209,16 @@ void runRequiredJobs(Qt3DRender::TestAspect *test)
updateWorldTransform.setManagers(test->nodeManagers());
updateWorldTransform.run();
- Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
- calcBVolume.setManagers(test->nodeManagers());
- calcBVolume.setRoot(test->sceneRoot());
- calcBVolume.run();
+ Qt3DCore::CalculateBoundingVolumeJob calcCBVolume;
+ calcCBVolume.setRoot(test->root());
+ calcCBVolume.run();
+ calcCBVolume.postFrame(nullptr);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcRBVolume;
+ calcRBVolume.setManagers(test->nodeManagers());
+ calcRBVolume.setFrontEndNodeManager(test);
+ calcRBVolume.setRoot(test->sceneRoot());
+ calcRBVolume.run();
Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
diff --git a/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp b/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp
index ee0be6647..a64f5de71 100644
--- a/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp
+++ b/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp
@@ -291,6 +291,7 @@ private Q_SLOTS:
// GIVEN
QScopedPointer<Qt3DRender::TestAspect> aspect(new Qt3DRender::TestAspect(entitySubtree));
+ aspect->registerTree(entitySubtree);
// WHEN
Qt3DRender::Render::Entity *backendRoot = aspect->nodeManagers()->renderNodesManager()->getOrCreateResource(entitySubtree->id());
@@ -308,6 +309,7 @@ private Q_SLOTS:
Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
calcBVolume.setManagers(aspect->nodeManagers());
calcBVolume.setRoot(backendRoot);
+ calcBVolume.setFrontEndNodeManager(aspect.data());
calcBVolume.run();
Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
diff --git a/tests/auto/render/raycastingjob/tst_raycastingjob.cpp b/tests/auto/render/raycastingjob/tst_raycastingjob.cpp
index 0f466b4d4..5c8a1d76f 100644
--- a/tests/auto/render/raycastingjob/tst_raycastingjob.cpp
+++ b/tests/auto/render/raycastingjob/tst_raycastingjob.cpp
@@ -32,12 +32,14 @@
#include <QtTest/QTest>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/qabstractfrontendnodemanager.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodevisitor_p.h>
#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/private/qaspectengine_p.h>
#include <Qt3DCore/private/qaspectjob_p.h>
+#include <Qt3DCore/private/calcboundingvolumejob_p.h>
#include <QtQuick/qquickwindow.h>
#include <Qt3DRender/QCamera>
@@ -104,7 +106,7 @@ QVector<Qt3DCore::NodeTreeChange> nodeTreeChangesForNodes(const QVector<Qt3DCore
return nodeTreeChanges;
}
-class TestAspect : public Qt3DRender::QRenderAspect
+class TestAspect : public Qt3DRender::QRenderAspect, public Qt3DCore::QAbstractFrontEndNodeManager
{
public:
TestAspect(Qt3DCore::QNode *root)
@@ -116,7 +118,8 @@ public:
Q_ASSERT(d_func()->m_aspectManager);
// do what QAspectEngine::setRootEntity does since we don't want to enter the simulation loop
- Qt3DCore::QEntityPtr proot(qobject_cast<Qt3DCore::QEntity *>(root), [](Qt3DCore::QEntity *) { });
+ m_root = qobject_cast<Qt3DCore::QEntity *>(root);
+ Qt3DCore::QEntityPtr proot(m_root, [](Qt3DCore::QEntity *) { });
Qt3DCore::QAspectEnginePrivate *aed = Qt3DCore::QAspectEnginePrivate::get(m_engine);
aed->m_root = proot;
aed->initialize();
@@ -127,6 +130,8 @@ public:
Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
Q_ASSERT(rootEntity);
m_sceneRoot = rootEntity;
+
+ registerTree(m_root);
}
~TestAspect()
@@ -150,13 +155,39 @@ public:
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(); }
+ Qt3DCore::QEntity *root() const { return m_root; }
Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
Qt3DCore::QAspectManager *aspectManager() const { return d_func()->m_aspectManager; }
Qt3DCore::QAspectEngine *aspectEngine() const { return m_engine; }
Qt3DCore::QChangeArbiter *arbiter() const { return d_func()->m_arbiter; }
+
+ void registerNode(Qt3DCore::QNode *node) { m_frontEndNodes.insert(node->id(), node); }
+ void registerTree(Qt3DCore::QEntity *root) {
+ using namespace Qt3DCore;
+ QNodeVisitor visitor;
+ visitor.traverse(root, [](QNode *) {}, [this](QEntity *entity) {
+ registerNode(entity);
+ const auto &components = entity->components();
+ for (const auto &c : components)
+ registerNode(c);
+ });
+ }
+ Qt3DCore::QNode *lookupNode(Qt3DCore::QNodeId id) const override { return m_frontEndNodes.value(id, nullptr); }
+ QVector<Qt3DCore::QNode *> lookupNodes(const QVector<Qt3DCore::QNodeId> &ids) const override {
+ QVector<Qt3DCore::QNode *> res;
+ for (const auto &id: ids) {
+ auto node = m_frontEndNodes.value(id, nullptr);
+ if (node)
+ res.push_back(node);
+ }
+ return res;
+ }
+
private:
Qt3DCore::QAspectEngine *m_engine;
+ Qt3DCore::QEntity *m_root;
Render::Entity *m_sceneRoot;
+ QHash<Qt3DCore::QNodeId, Qt3DCore::QNode *> m_frontEndNodes;
};
} // namespace Qt3DRender
@@ -176,10 +207,16 @@ void runRequiredJobs(Qt3DRender::TestAspect *test)
updateWorldTransform.setManagers(test->nodeManagers());
updateWorldTransform.run();
- Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
- calcBVolume.setManagers(test->nodeManagers());
- calcBVolume.setRoot(test->sceneRoot());
- calcBVolume.run();
+ Qt3DCore::CalculateBoundingVolumeJob calcCBVolume;
+ calcCBVolume.setRoot(test->root());
+ calcCBVolume.run();
+ calcCBVolume.postFrame(nullptr);
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcRBVolume;
+ calcRBVolume.setManagers(test->nodeManagers());
+ calcRBVolume.setFrontEndNodeManager(test);
+ calcRBVolume.setRoot(test->sceneRoot());
+ calcRBVolume.run();
Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
@@ -254,6 +291,9 @@ private Q_SLOTS:
// Runs Required jobs
runRequiredJobs(test.data());
+ // Clear changed nodes
+ test->arbiter()->takeDirtyFrontEndNodes();
+
Qt3DRender::Render::RayCaster *backendRayCaster = test->nodeManagers()->rayCasterManager()->lookupResource(rayCaster->id());
QVERIFY(backendRayCaster);
@@ -270,6 +310,7 @@ private Q_SLOTS:
QVERIFY(!backendRayCaster->isEnabled());
QVERIFY(!rayCaster->isEnabled());
auto dirtyNodes = test->arbiter()->takeDirtyFrontEndNodes();
+ qDebug() << dirtyNodes;
QCOMPARE(dirtyNodes.count(), 1); // hits & disable
QCOMPARE(rayCaster->hits().size(), numIntersections);
@@ -313,6 +354,9 @@ private Q_SLOTS:
// Runs Required jobs
runRequiredJobs(test.data());
+ // Clear changed nodes
+ test->arbiter()->takeDirtyFrontEndNodes();
+
Qt3DRender::Render::RayCaster *backendRayCaster = test->nodeManagers()->rayCasterManager()->lookupResource(rayCaster->id());
QVERIFY(backendRayCaster);