diff options
author | Mike Krus <mike.krus@kdab.com> | 2020-03-07 09:27:16 +0000 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2020-04-23 10:46:06 +0100 |
commit | 60f42119fe5c341880f4576e0c9ad8d99ee277d5 (patch) | |
tree | e3a4992e501593c64ad506c13c0ddae87e9f5018 | |
parent | ee476605629a74fb824d3f014deb6e6be9e40e9f (diff) | |
download | qt3d-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.qml | 6 | ||||
-rw-r--r-- | examples/qt3d/scene3d/main.qml | 21 | ||||
-rw-r--r-- | src/core/geometry/qgeometryview.cpp | 2 | ||||
-rw-r--r-- | src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp | 2 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 10 | ||||
-rw-r--r-- | src/render/geometry/geometryrenderer.cpp | 18 | ||||
-rw-r--r-- | src/render/geometry/geometryrenderer_p.h | 3 | ||||
-rw-r--r-- | src/render/jobs/calcboundingvolumejob.cpp | 135 | ||||
-rw-r--r-- | src/render/jobs/calcboundingvolumejob_p.h | 12 | ||||
-rw-r--r-- | tests/auto/render/boundingsphere/tst_boundingsphere.cpp | 73 | ||||
-rw-r--r-- | tests/auto/render/commons/testaspect.h | 27 | ||||
-rw-r--r-- | tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp | 46 | ||||
-rw-r--r-- | tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp | 2 | ||||
-rw-r--r-- | tests/auto/render/raycastingjob/tst_raycastingjob.cpp | 56 |
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); |