diff options
Diffstat (limited to 'src/render/jobs')
19 files changed, 335 insertions, 284 deletions
diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 68eb308c5..113dc34ce 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -51,6 +51,7 @@ #include <Qt3DRender/private/buffer_p.h> #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/buffervisitor_p.h> +#include <Qt3DRender/private/entityaccumulator_p.h> #include <QtCore/qmath.h> #if QT_CONFIG(concurrent) @@ -65,28 +66,6 @@ namespace Render { namespace { -QVector<Geometry*> calculateLocalBoundingVolume(NodeManagers *manager, Entity *node); - -struct UpdateBoundFunctor -{ - NodeManagers *manager; - - // This define is required to work with QtConcurrent - typedef QVector<Geometry *> result_type; - QVector<Geometry *> operator ()(Qt3DRender::Render::Entity *node) - { - return calculateLocalBoundingVolume(manager, node); - } -}; - -struct ReduceUpdateBoundFunctor -{ - void operator ()(QVector<Geometry *> &result, const QVector<Geometry *> &values) - { - result += values; - } -}; - class BoundingVolumeCalculator { public: @@ -318,23 +297,29 @@ QVector<Geometry *> calculateLocalBoundingVolume(NodeManagers *manager, Entity * } } -#if QT_CONFIG(concurrent) - const QVector<Qt3DRender::Render::Entity *> children = node->children(); - if (children.size() > 1) { - UpdateBoundFunctor functor; - functor.manager = manager; - ReduceUpdateBoundFunctor reduceFunctor; - updatedGeometries += QtConcurrent::blockingMappedReduced<decltype(updatedGeometries)>(children, functor, reduceFunctor); - } else -#endif - { - const auto children = node->children(); - for (Entity *child : children) - updatedGeometries += calculateLocalBoundingVolume(manager, child); - } return updatedGeometries; } +struct UpdateBoundFunctor +{ + NodeManagers *manager; + + // This define is required to work with QtConcurrent + typedef QVector<Geometry *> result_type; + QVector<Geometry *> operator ()(Qt3DRender::Render::Entity *node) + { + return calculateLocalBoundingVolume(manager, node); + } +}; + +struct ReduceUpdateBoundFunctor +{ + void operator ()(QVector<Geometry *> &result, const QVector<Geometry *> &values) + { + result += values; + } +}; + } // anonymous CalculateBoundingVolumeJob::CalculateBoundingVolumeJob() @@ -346,7 +331,26 @@ CalculateBoundingVolumeJob::CalculateBoundingVolumeJob() void CalculateBoundingVolumeJob::run() { - const QVector<Geometry *> updatedGeometries = calculateLocalBoundingVolume(m_manager, m_node); + EntityAccumulator accumulator([](Entity *entity) { + return !entity->componentUuid<GeometryRenderer>().isNull(); + }, m_manager); + auto entities = accumulator.apply(m_node); + + QVector<Geometry *> updatedGeometries; + updatedGeometries.reserve(entities.size()); + +#if QT_CONFIG(concurrent) + if (entities.size() > 1) { + UpdateBoundFunctor functor; + functor.manager = m_manager; + ReduceUpdateBoundFunctor reduceFunctor; + updatedGeometries += QtConcurrent::blockingMappedReduced<decltype(updatedGeometries)>(entities, functor, reduceFunctor); + } else +#endif + { + for (Entity *child : entities) + updatedGeometries += calculateLocalBoundingVolume(m_manager, child); + } // Send extent updates to frontend for (Geometry *geometry : updatedGeometries) diff --git a/src/render/jobs/computefilteredboundingvolumejob.cpp b/src/render/jobs/computefilteredboundingvolumejob.cpp index d8a7b5094..02852685c 100644 --- a/src/render/jobs/computefilteredboundingvolumejob.cpp +++ b/src/render/jobs/computefilteredboundingvolumejob.cpp @@ -44,6 +44,8 @@ #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <QThread> @@ -54,16 +56,18 @@ namespace Render { namespace { -void expandWorldBoundingVolume(Qt3DRender::Render::Sphere *sphere, +void expandWorldBoundingVolume(NodeManagers *manager, + Qt3DRender::Render::Sphere *sphere, Qt3DRender::Render::Entity *node, Qt3DRender::Render::Entity *excludeSubTree) { Qt3DRender::Render::Sphere childSphere(*node->worldBoundingVolume()); // Go to the nodes that have the most depth - const auto children = node->children(); - for (Entity *c : children) { - if (c != excludeSubTree) - expandWorldBoundingVolume(&childSphere, c, excludeSubTree); + const auto childrenHandles = node->childrenHandles(); + for (const HEntity &handle : childrenHandles) { + Entity *c = manager->renderNodesManager()->data(handle); + if (c && c != excludeSubTree) + expandWorldBoundingVolume(manager, &childSphere, c, excludeSubTree); } sphere->expandToContain(childSphere); } @@ -73,6 +77,7 @@ void expandWorldBoundingVolume(Qt3DRender::Render::Sphere *sphere, ComputeFilteredBoundingVolumeJob::ComputeFilteredBoundingVolumeJob() : m_root(nullptr) , m_ignoreSubTree(nullptr) + , m_manager(nullptr) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); } @@ -82,6 +87,11 @@ void ComputeFilteredBoundingVolumeJob::setRoot(Entity *root) m_root = root; } +void ComputeFilteredBoundingVolumeJob::setManagers(NodeManagers *manager) +{ + m_manager = manager; +} + void ComputeFilteredBoundingVolumeJob::ignoreSubTree(Entity *node) { m_ignoreSubTree = node; @@ -113,7 +123,7 @@ void ComputeFilteredBoundingVolumeJob::run() } Qt3DRender::Render::Sphere sphere; - expandWorldBoundingVolume(&sphere, m_root, m_ignoreSubTree); + expandWorldBoundingVolume(m_manager, &sphere, m_root, m_ignoreSubTree); finished(sphere); qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); diff --git a/src/render/jobs/computefilteredboundingvolumejob_p.h b/src/render/jobs/computefilteredboundingvolumejob_p.h index 797a685ee..d2aca575c 100644 --- a/src/render/jobs/computefilteredboundingvolumejob_p.h +++ b/src/render/jobs/computefilteredboundingvolumejob_p.h @@ -62,6 +62,7 @@ namespace Qt3DRender { namespace Render { class Entity; +class NodeManagers; class Sphere; class Q_3DRENDERSHARED_PRIVATE_EXPORT ComputeFilteredBoundingVolumeJob : public Qt3DCore::QAspectJob @@ -70,6 +71,7 @@ public: ComputeFilteredBoundingVolumeJob(); void setRoot(Entity *root); + void setManagers(NodeManagers *manager); void ignoreSubTree(Entity *node); void run() override; @@ -79,6 +81,7 @@ protected: private: Entity *m_root; Entity *m_ignoreSubTree; + NodeManagers *m_manager; }; typedef QSharedPointer<ComputeFilteredBoundingVolumeJob> ComputeFilteredBoundingVolumeJobPtr; diff --git a/src/render/jobs/expandboundingvolumejob.cpp b/src/render/jobs/expandboundingvolumejob.cpp index ec175f312..d63934b54 100644 --- a/src/render/jobs/expandboundingvolumejob.cpp +++ b/src/render/jobs/expandboundingvolumejob.cpp @@ -44,6 +44,8 @@ #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DRender/private/sphere_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <QThread> @@ -54,19 +56,25 @@ namespace Render { namespace { -void expandWorldBoundingVolume(Qt3DRender::Render::Entity *node) +void expandWorldBoundingVolume(NodeManagers *manager, Entity *node) { // Go to the nodes that have the most depth - const auto children = node->children(); - for (Entity *c : children) - expandWorldBoundingVolume(c); + const auto childrenHandles = node->childrenHandles(); + for (const HEntity &handle : childrenHandles) { + Entity *c = manager->renderNodesManager()->data(handle); + if (c) + expandWorldBoundingVolume(manager, c); + } // Then traverse back from leaf to root // Initialize parent bounding volume to be equal to that of the first child - if (!children.empty()) { + if (!childrenHandles.empty()) { Qt3DRender::Render::Sphere *parentBoundingVolume = node->worldBoundingVolumeWithChildren(); - for (Entity *c : children) - parentBoundingVolume->expandToContain(*c->worldBoundingVolumeWithChildren()); + for (const HEntity &handle : childrenHandles) { + Entity *c = manager->renderNodesManager()->data(handle); + if (c) + parentBoundingVolume->expandToContain(*c->worldBoundingVolumeWithChildren()); + } } } @@ -74,6 +82,7 @@ void expandWorldBoundingVolume(Qt3DRender::Render::Entity *node) ExpandBoundingVolumeJob::ExpandBoundingVolumeJob() : m_node(nullptr) + , m_manager(nullptr) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); } @@ -83,6 +92,11 @@ void ExpandBoundingVolumeJob::setRoot(Entity *root) m_node = root; } +void ExpandBoundingVolumeJob::setManagers(NodeManagers *manager) +{ + m_manager = manager; +} + void ExpandBoundingVolumeJob::run() { // Expand worldBoundingVolumeWithChildren of each node that has children by the @@ -90,7 +104,7 @@ void ExpandBoundingVolumeJob::run() // TODO: Implement this using a parallel_for qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); - expandWorldBoundingVolume(m_node); + expandWorldBoundingVolume(m_manager, m_node); qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); } diff --git a/src/render/jobs/expandboundingvolumejob_p.h b/src/render/jobs/expandboundingvolumejob_p.h index c577c90e2..a2745b456 100644 --- a/src/render/jobs/expandboundingvolumejob_p.h +++ b/src/render/jobs/expandboundingvolumejob_p.h @@ -62,6 +62,7 @@ namespace Qt3DRender { namespace Render { class Entity; +class NodeManagers; class Q_3DRENDERSHARED_PRIVATE_EXPORT ExpandBoundingVolumeJob : public Qt3DCore::QAspectJob { @@ -69,10 +70,12 @@ public: ExpandBoundingVolumeJob(); void setRoot(Entity *root); + void setManagers(NodeManagers *manager); void run() override; private: Entity *m_node; + NodeManagers *m_manager; }; typedef QSharedPointer<ExpandBoundingVolumeJob> ExpandBoundingVolumeJobPtr; diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp index 7ebcead37..17ca60bff 100644 --- a/src/render/jobs/framecleanupjob.cpp +++ b/src/render/jobs/framecleanupjob.cpp @@ -78,23 +78,22 @@ void FrameCleanupJob::run() void FrameCleanupJob::updateBoundingVolumesDebug(Entity *node) { + Q_UNUSED(node); #if 0 - BoundingVolumeDebug *debugBV = node->renderComponent<BoundingVolumeDebug>(); - if (debugBV) { - Qt3DRender::Render::Sphere s; - if (!debugBV->isRecursive()) { - s = *node->worldBoundingVolume(); - } else { - s = *node->worldBoundingVolumeWithChildren(); + node->traverse([](Entity *node) { + BoundingVolumeDebug *debugBV = node->renderComponent<BoundingVolumeDebug>(); + if (debugBV) { + Qt3DRender::Render::Sphere s; + if (!debugBV->isRecursive()) { + s = *node->worldBoundingVolume(); + } else { + s = *node->worldBoundingVolumeWithChildren(); + } + debugBV->setRadius(s.radius()); + debugBV->setCenter(s.center()); } - debugBV->setRadius(s.radius()); - debugBV->setCenter(s.center()); - } + }); - - const auto children = node->children(); - for (Entity *c : children) - updateBoundingVolumesDebug(c); #endif } diff --git a/src/render/jobs/frustumcullingjob.cpp b/src/render/jobs/frustumcullingjob.cpp index 1a03b691d..0922fb0cb 100644 --- a/src/render/jobs/frustumcullingjob.cpp +++ b/src/render/jobs/frustumcullingjob.cpp @@ -43,6 +43,8 @@ #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/renderview_p.h> #include <Qt3DRender/private/sphere_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> QT_BEGIN_NAMESPACE @@ -53,6 +55,7 @@ namespace Render { FrustumCullingJob::FrustumCullingJob() : Qt3DCore::QAspectJob() , m_root(nullptr) + , m_manager(nullptr) , m_active(false) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, 0); @@ -83,27 +86,25 @@ void FrustumCullingJob::run() void FrustumCullingJob::cullScene(Entity *e, const Plane *planes) { - const Sphere *s = e->worldBoundingVolumeWithChildren(); - - // Unrolled loop - if (Vector3D::dotProduct(s->center(), planes[0].normal) + planes[0].d < -s->radius()) - return; - if (Vector3D::dotProduct(s->center(), planes[1].normal) + planes[1].d < -s->radius()) - return; - if (Vector3D::dotProduct(s->center(), planes[2].normal) + planes[2].d < -s->radius()) - return; - if (Vector3D::dotProduct(s->center(), planes[3].normal) + planes[3].d < -s->radius()) - return; - if (Vector3D::dotProduct(s->center(), planes[4].normal) + planes[4].d < -s->radius()) - return; - if (Vector3D::dotProduct(s->center(), planes[5].normal) + planes[5].d < -s->radius()) - return; - - m_visibleEntities.push_back(e); - - const QVector<Entity *> children = e->children(); - for (Entity *c : children) - cullScene(c, planes); + e->traverse([planes, this](Entity *e) { + const Sphere *s = e->worldBoundingVolumeWithChildren(); + + // Unrolled loop + if (Vector3D::dotProduct(s->center(), planes[0].normal) + planes[0].d < -s->radius()) + return; + if (Vector3D::dotProduct(s->center(), planes[1].normal) + planes[1].d < -s->radius()) + return; + if (Vector3D::dotProduct(s->center(), planes[2].normal) + planes[2].d < -s->radius()) + return; + if (Vector3D::dotProduct(s->center(), planes[3].normal) + planes[3].d < -s->radius()) + return; + if (Vector3D::dotProduct(s->center(), planes[4].normal) + planes[4].d < -s->radius()) + return; + if (Vector3D::dotProduct(s->center(), planes[5].normal) + planes[5].d < -s->radius()) + return; + + m_visibleEntities.push_back(e); + }); } } // Render diff --git a/src/render/jobs/frustumcullingjob_p.h b/src/render/jobs/frustumcullingjob_p.h index f81e4c5b9..cddbbd409 100644 --- a/src/render/jobs/frustumcullingjob_p.h +++ b/src/render/jobs/frustumcullingjob_p.h @@ -63,6 +63,7 @@ namespace Render { class Entity; class EntityManager; +class NodeManagers; struct Plane; class FrustumCullingJob : public Qt3DCore::QAspectJob @@ -73,6 +74,7 @@ public: QT3D_ALIGNED_MALLOC_AND_FREE() inline void setRoot(Entity *root) Q_DECL_NOTHROW { m_root = root; } + inline void setManagers(NodeManagers *manager) Q_DECL_NOTHROW { m_manager = manager; } inline void setActive(bool active) Q_DECL_NOTHROW { m_active = active; } inline bool isActive() const Q_DECL_NOTHROW { return m_active; } inline void setViewProjection(const Matrix4x4 &viewProjection) Q_DECL_NOTHROW { m_viewProjection = viewProjection; } @@ -86,6 +88,7 @@ private: void cullScene(Entity *e, const Plane *planes); Matrix4x4 m_viewProjection; Entity *m_root; + NodeManagers *m_manager; QVector<Entity *> m_visibleEntities; bool m_active; }; diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp index 39069e374..1d22e8645 100644 --- a/src/render/jobs/pickboundingvolumeutils.cpp +++ b/src/render/jobs/pickboundingvolumeutils.cpp @@ -800,12 +800,15 @@ bool HierarchicalEntityPicker::collectHits(NodeManagers *manager, Entity *root) } // and pick children - const auto children = current.entity->children(); - for (Entity *child: children) { - ObjectPicker *childPicker = child->renderComponent<ObjectPicker>(); - worklist.push_back({child, current.hasObjectPicker || childPicker, - current.recursiveLayers + recursiveLayers, - (childPicker ? childPicker->priority() : current.priority)}); + const auto childrenHandles = current.entity->childrenHandles(); + for (const HEntity &handle : childrenHandles) { + Entity *child = manager->renderNodesManager()->data(handle); + if (child) { + ObjectPicker *childPicker = child->renderComponent<ObjectPicker>(); + worklist.push_back({child, current.hasObjectPicker || childPicker, + current.recursiveLayers + recursiveLayers, + (childPicker ? childPicker->priority() : current.priority)}); + } } } diff --git a/src/render/jobs/raycastingjob.cpp b/src/render/jobs/raycastingjob.cpp index 887f203bf..f3571c210 100644 --- a/src/render/jobs/raycastingjob.cpp +++ b/src/render/jobs/raycastingjob.cpp @@ -50,6 +50,7 @@ #include <Qt3DRender/private/renderer_p.h> #include <Qt3DRender/private/rendersettings_p.h> #include <Qt3DRender/private/trianglesvisitor_p.h> +#include <Qt3DRender/private/entityvisitor_p.h> QT_BEGIN_NAMESPACE @@ -59,43 +60,23 @@ using namespace Render; namespace { -class EntityCasterGatherer +class EntityCasterGatherer : public EntityVisitor { public: using EntityCasterList = QVector<QPair<Entity *, RayCaster*>>; + EntityCasterList m_result; - explicit EntityCasterGatherer(Entity *root) : m_root(root), m_needsRefresh(true) { } + explicit EntityCasterGatherer(NodeManagers *manager) : EntityVisitor(manager) { setPruneDisabled(true); } - EntityCasterList result() const { - if (m_needsRefresh) { - m_result.clear(); - m_result = gatherEntities(m_root, std::move(m_result)); - m_needsRefresh = false; + Operation visit(Entity *entity) override { + QVector<RayCaster *> components = entity->renderComponents<RayCaster>(); + for (const auto c: qAsConst(components)) { + if (c->isEnabled()) + m_result.push_back(qMakePair(entity, c)); } - return m_result; - } - -private: - EntityCasterList gatherEntities(Entity *entity, EntityCasterList entities) const - { - if (entity != nullptr && entity->isEnabled()) { - QVector<RayCaster *> components = entity->renderComponents<RayCaster>(); - for (const auto c: qAsConst(components)) { - if (c->isEnabled()) - entities.push_back(qMakePair(entity, c)); - } - // Traverse children - const auto children = entity->children(); - for (Entity *child : children) - entities = gatherEntities(child, std::move(entities)); - } - return entities; + return Continue; } - - Entity *m_root; - mutable EntityCasterList m_result; - mutable bool m_needsRefresh; }; } // anonymous @@ -145,8 +126,9 @@ bool RayCastingJob::runHelper() m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace; const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance(); - EntityCasterGatherer gatherer(m_node); - const EntityCasterGatherer::EntityCasterList &entities = gatherer.result(); + EntityCasterGatherer gatherer(m_manager); + gatherer.apply(m_node); + const EntityCasterGatherer::EntityCasterList &entities = gatherer.m_result; PickingUtils::ViewportCameraAreaGatherer vcaGatherer; const QVector<PickingUtils::ViewportCameraAreaDetails> vcaDetails = vcaGatherer.gather(m_frameGraphRoot); diff --git a/src/render/jobs/updateentitylayersjob.cpp b/src/render/jobs/updateentitylayersjob.cpp index 1fa34684f..2c5e38364 100644 --- a/src/render/jobs/updateentitylayersjob.cpp +++ b/src/render/jobs/updateentitylayersjob.cpp @@ -49,19 +49,6 @@ namespace Qt3DRender { namespace Render { -namespace { - -void addLayerIdToEntityChildren(const QVector<Entity *> &children, - const Qt3DCore::QNodeId layerId) -{ - for (Entity *child : children) { - child->addRecursiveLayerId(layerId); - addLayerIdToEntityChildren(child->children(), layerId); - } -} - -} // anonymous - UpdateEntityLayersJob::UpdateEntityLayersJob() : m_manager(nullptr) { @@ -93,7 +80,9 @@ void UpdateEntityLayersJob::run() Layer *layer = layerManager->lookupResource(layerId); if (layer->recursive()) { // Find all children of the entity and add the layers to them - addLayerIdToEntityChildren(entity->children(), layerId); + entity->traverse([layerId](Entity *e) { + e->addRecursiveLayerId(layerId); + }); } } } diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp index e4b651949..b5349a2c1 100644 --- a/src/render/jobs/updatelevelofdetailjob.cpp +++ b/src/render/jobs/updatelevelofdetailjob.cpp @@ -39,6 +39,7 @@ #include "updatelevelofdetailjob_p.h" #include <Qt3DRender/QLevelOfDetail> +#include <Qt3DRender/private/entityvisitor_p.h> #include <Qt3DRender/private/job_common_p.h> #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/managers_p.h> @@ -57,9 +58,145 @@ double approxRollingAverage(double avg, double input) { return avg; } +class LODUpdateVisitor : public Qt3DRender::Render::EntityVisitor +{ +public: + LODUpdateVisitor(double filterValue, Qt3DRender::Render::FrameGraphNode *frameGraphRoot, Qt3DRender::Render::NodeManagers *manager) + : Qt3DRender::Render::EntityVisitor(manager) + , m_filterValue(filterValue) + , m_frameGraphRoot(frameGraphRoot) + { + } + + double filterValue() const { return m_filterValue; } + + Operation visit(Qt3DRender::Render::Entity *entity = nullptr) override { + using namespace Qt3DRender; + using namespace Qt3DRender::Render; + + if (!entity->isEnabled()) + return Prune; // skip disabled sub-trees, since their bounding box is probably not valid anyway + + QVector<LevelOfDetail *> lods = entity->renderComponents<LevelOfDetail>(); + if (!lods.empty()) { + LevelOfDetail* lod = lods.front(); // other lods are ignored + + if (lod->isEnabled() && !lod->thresholds().isEmpty()) { + switch (lod->thresholdType()) { + case QLevelOfDetail::DistanceToCameraThreshold: + updateEntityLodByDistance(entity, lod); + break; + case QLevelOfDetail::ProjectedScreenPixelSizeThreshold: + updateEntityLodByScreenArea(entity, lod); + break; + default: + Q_ASSERT(false); + break; + } + } + } + + return Continue; + } + +private: + double m_filterValue = 0.; + Qt3DRender::Render::FrameGraphNode *m_frameGraphRoot; + + void updateEntityLodByDistance(Qt3DRender::Render::Entity *entity, Qt3DRender::Render::LevelOfDetail *lod) + { + using namespace Qt3DRender; + using namespace Qt3DRender::Render; + + Matrix4x4 viewMatrix; + Matrix4x4 projectionMatrix; + if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix)) + return; + + const QVector<qreal> thresholds = lod->thresholds(); + Vector3D center(lod->center()); + if (lod->hasBoundingVolumeOverride() || entity->worldBoundingVolume() == nullptr) { + center = *entity->worldTransform() * center; + } else { + center = entity->worldBoundingVolume()->center(); + } + + const Vector3D tcenter = viewMatrix * center; + const float dist = tcenter.length(); + const int n = thresholds.size(); + for (int i=0; i<n; ++i) { + if (dist <= thresholds[i] || i == n -1) { + m_filterValue = approxRollingAverage<30>(m_filterValue, i); + i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1); + if (lod->currentIndex() != i) + lod->setCurrentIndex(i); + break; + } + } + } + + void updateEntityLodByScreenArea(Qt3DRender::Render::Entity *entity, Qt3DRender::Render::LevelOfDetail *lod) + { + using namespace Qt3DRender; + using namespace Qt3DRender::Render; + + Matrix4x4 viewMatrix; + Matrix4x4 projectionMatrix; + if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix)) + return; + + PickingUtils::ViewportCameraAreaGatherer vcaGatherer(lod->camera()); + const QVector<PickingUtils::ViewportCameraAreaDetails> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); + if (vcaTriplets.isEmpty()) + return; + + const PickingUtils::ViewportCameraAreaDetails &vca = vcaTriplets.front(); + + const QVector<qreal> thresholds = lod->thresholds(); + Sphere bv(Vector3D(lod->center()), lod->radius()); + if (!lod->hasBoundingVolumeOverride() && entity->worldBoundingVolume() != nullptr) { + bv = *(entity->worldBoundingVolume()); + } else { + bv.transform(*entity->worldTransform()); + } + + bv.transform(projectionMatrix * viewMatrix); + const float sideLength = bv.radius() * 2.f; + float area = vca.viewport.width() * sideLength * vca.viewport.height() * sideLength; + + const QRect r = windowViewport(vca.area, vca.viewport); + area = std::sqrt(area * r.width() * r.height()); + + const int n = thresholds.size(); + for (int i = 0; i < n; ++i) { + if (thresholds[i] < area || i == n -1) { + m_filterValue = approxRollingAverage<30>(m_filterValue, i); + i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1); + if (lod->currentIndex() != i) + lod->setCurrentIndex(i); + break; + } + } + } + + QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const + { + if (area.isValid()) { + const int areaWidth = area.width(); + const int areaHeight = area.height(); + return QRect(relativeViewport.x() * areaWidth, + (1.0 - relativeViewport.y() - relativeViewport.height()) * areaHeight, + relativeViewport.width() * areaWidth, + relativeViewport.height() * areaHeight); + } + return relativeViewport.toRect(); + } +}; + } -namespace Qt3DRender { + +namespace Qt3DRender { namespace Render { UpdateLevelOfDetailJob::UpdateLevelOfDetailJob() @@ -98,119 +235,13 @@ void UpdateLevelOfDetailJob::run() if (m_manager->levelOfDetailManager()->count() == 0) return; - updateEntityLod(m_root); -} - -QRect UpdateLevelOfDetailJob::windowViewport(const QSize &area, const QRectF &relativeViewport) const -{ - if (area.isValid()) { - const int areaWidth = area.width(); - const int areaHeight = area.height(); - return QRect(relativeViewport.x() * areaWidth, - (1.0 - relativeViewport.y() - relativeViewport.height()) * areaHeight, - relativeViewport.width() * areaWidth, - relativeViewport.height() * areaHeight); - } - return relativeViewport.toRect(); -} - -void UpdateLevelOfDetailJob::updateEntityLod(Entity *entity) -{ - if (!entity->isEnabled()) - return; // skip disabled sub-trees, since their bounding box is probably not valid anyway - - QVector<LevelOfDetail *> lods = entity->renderComponents<LevelOfDetail>(); - if (!lods.empty()) { - LevelOfDetail* lod = lods.front(); // other lods are ignored - - if (lod->isEnabled() && !lod->thresholds().isEmpty()) { - switch (lod->thresholdType()) { - case QLevelOfDetail::DistanceToCameraThreshold: - updateEntityLodByDistance(entity, lod); - break; - case QLevelOfDetail::ProjectedScreenPixelSizeThreshold: - updateEntityLodByScreenArea(entity, lod); - break; - default: - Q_ASSERT(false); - break; - } - } - } - - const auto children = entity->children(); - for (Qt3DRender::Render::Entity *child : children) - updateEntityLod(child); -} - -void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDetail *lod) -{ - Matrix4x4 viewMatrix; - Matrix4x4 projectionMatrix; - if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix)) - return; - - const QVector<qreal> thresholds = lod->thresholds(); - Vector3D center(lod->center()); - if (lod->hasBoundingVolumeOverride() || entity->worldBoundingVolume() == nullptr) { - center = *entity->worldTransform() * center; - } else { - center = entity->worldBoundingVolume()->center(); - } - - const Vector3D tcenter = viewMatrix * center; - const float dist = tcenter.length(); - const int n = thresholds.size(); - for (int i=0; i<n; ++i) { - if (dist <= thresholds[i] || i == n -1) { - m_filterValue = approxRollingAverage<30>(m_filterValue, i); - i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1); - if (lod->currentIndex() != i) - lod->setCurrentIndex(i); - break; - } - } -} - -void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOfDetail *lod) -{ - Matrix4x4 viewMatrix; - Matrix4x4 projectionMatrix; - if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix)) - return; - - PickingUtils::ViewportCameraAreaGatherer vcaGatherer(lod->camera()); - const QVector<PickingUtils::ViewportCameraAreaDetails> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot); - if (vcaTriplets.isEmpty()) - return; - - const PickingUtils::ViewportCameraAreaDetails &vca = vcaTriplets.front(); - const QVector<qreal> thresholds = lod->thresholds(); - Sphere bv(Vector3D(lod->center()), lod->radius()); - if (!lod->hasBoundingVolumeOverride() && entity->worldBoundingVolume() != nullptr) { - bv = *(entity->worldBoundingVolume()); - } else { - bv.transform(*entity->worldTransform()); - } + if (m_manager->levelOfDetailManager()->count() == 0) + return; // no LODs, lets bail out early - bv.transform(projectionMatrix * viewMatrix); - const float sideLength = bv.radius() * 2.f; - float area = vca.viewport.width() * sideLength * vca.viewport.height() * sideLength; - - const QRect r = windowViewport(vca.area, vca.viewport); - area = std::sqrt(area * r.width() * r.height()); - - const int n = thresholds.size(); - for (int i = 0; i < n; ++i) { - if (thresholds[i] < area || i == n -1) { - m_filterValue = approxRollingAverage<30>(m_filterValue, i); - i = qBound(0, static_cast<int>(qRound(m_filterValue)), n - 1); - if (lod->currentIndex() != i) - lod->setCurrentIndex(i); - break; - } - } + LODUpdateVisitor visitor(m_filterValue, m_frameGraphRoot, m_manager); + visitor.apply(m_root); + m_filterValue = visitor.filterValue(); } } // Render diff --git a/src/render/jobs/updatelevelofdetailjob_p.h b/src/render/jobs/updatelevelofdetailjob_p.h index c7045ee7f..3c7d00d2c 100644 --- a/src/render/jobs/updatelevelofdetailjob_p.h +++ b/src/render/jobs/updatelevelofdetailjob_p.h @@ -81,12 +81,6 @@ public: Entity *root() const { return m_root; } private: - void updateEntityLod(Entity *entity); - void updateEntityLodByDistance(Entity *entity, LevelOfDetail *lod); - void updateEntityLodByScreenArea(Entity *entity, LevelOfDetail *lod); - - QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const; - NodeManagers *m_manager; FrameGraphNode *m_frameGraphRoot; Entity *m_root; diff --git a/src/render/jobs/updateskinningpalettejob.cpp b/src/render/jobs/updateskinningpalettejob.cpp index 1ee9101f9..0f5d3d6d6 100644 --- a/src/render/jobs/updateskinningpalettejob.cpp +++ b/src/render/jobs/updateskinningpalettejob.cpp @@ -79,7 +79,11 @@ void UpdateSkinningPaletteJob::run() // Find all the armature components and update their skinning palettes QVector<HArmature> dirtyArmatures; - findDirtyArmatures(m_root, dirtyArmatures); + m_root->traverse([&dirtyArmatures](Entity *entity) { + const auto armatureHandle = entity->componentHandle<Armature>(); + if (!armatureHandle.isNull() && !dirtyArmatures.contains(armatureHandle)) + dirtyArmatures.push_back(armatureHandle); + }); // Update the skeleton for each dirty armature auto skeletonManager = m_nodeManagers->skeletonManager(); @@ -96,22 +100,6 @@ void UpdateSkinningPaletteJob::run() } } -void UpdateSkinningPaletteJob::findDirtyArmatures(Entity *entity, - QVector<HArmature> &armatures) const -{ - // Just return all enabled armatures found on entities for now - // TODO: Be smarter about limiting which armatures we update. For e.g. only - // those with skeletons that have changed and only those that are within view - // of one or more renderviews. - const auto armatureHandle = entity->componentHandle<Armature>(); - if (!armatureHandle.isNull() && !armatures.contains(armatureHandle)) - armatures.push_back(armatureHandle); - - const auto children = entity->children(); - for (const auto child : children) - findDirtyArmatures(child, armatures); -} - } // namespace Render } // namespace Qt3DRender diff --git a/src/render/jobs/updateskinningpalettejob_p.h b/src/render/jobs/updateskinningpalettejob_p.h index 9e230f143..c52e0841c 100644 --- a/src/render/jobs/updateskinningpalettejob_p.h +++ b/src/render/jobs/updateskinningpalettejob_p.h @@ -75,7 +75,6 @@ public: protected: void run() override; - void findDirtyArmatures(Entity *entity, QVector<HArmature> &armatures) const; NodeManagers *m_nodeManagers; Entity *m_root; QVector<HJoint> m_dirtyJoints; diff --git a/src/render/jobs/updatetreeenabledjob.cpp b/src/render/jobs/updatetreeenabledjob.cpp index 6475ea78c..e97fc6414 100644 --- a/src/render/jobs/updatetreeenabledjob.cpp +++ b/src/render/jobs/updatetreeenabledjob.cpp @@ -41,6 +41,8 @@ #include <Qt3DRender/private/entity_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <QThread> @@ -51,14 +53,17 @@ namespace Render { namespace { -void updateTreeEnabled(Entity *node, bool parentEnabled) +void updateTreeEnabled(NodeManagers *manager, Entity *node, bool parentEnabled) { const bool treeEnabled = node->isEnabled() && parentEnabled; node->setTreeEnabled(treeEnabled); - const QVector<Entity*> children = node->children(); - for (Entity *child : children) - updateTreeEnabled(child, treeEnabled); + const auto childrenHandles = node->childrenHandles(); + for (const HEntity &handle : childrenHandles) { + Entity *child = manager->renderNodesManager()->data(handle); + if (child) + updateTreeEnabled(manager, child, treeEnabled); + } } } @@ -75,10 +80,15 @@ void UpdateTreeEnabledJob::setRoot(Entity *root) m_node = root; } +void UpdateTreeEnabledJob::setManagers(NodeManagers *manager) +{ + m_manager = manager; +} + void UpdateTreeEnabledJob::run() { - if (m_node) - updateTreeEnabled(m_node, true); + if (m_node && m_manager) + updateTreeEnabled(m_manager, m_node, true); } } // namespace Render diff --git a/src/render/jobs/updatetreeenabledjob_p.h b/src/render/jobs/updatetreeenabledjob_p.h index 6eac75ea6..ba28998bc 100644 --- a/src/render/jobs/updatetreeenabledjob_p.h +++ b/src/render/jobs/updatetreeenabledjob_p.h @@ -62,6 +62,7 @@ namespace Qt3DRender { namespace Render { class Entity; +class NodeManagers; class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateTreeEnabledJob : public Qt3DCore::QAspectJob { @@ -69,10 +70,12 @@ public: UpdateTreeEnabledJob(); void setRoot(Entity *root); + void setManagers(NodeManagers *manager); void run() override; private: Entity *m_node; + NodeManagers *m_manager; }; typedef QSharedPointer<UpdateTreeEnabledJob> UpdateTreeEnabledJobPtr; diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp index c56ed8507..1a9697843 100644 --- a/src/render/jobs/updateworldtransformjob.cpp +++ b/src/render/jobs/updateworldtransformjob.cpp @@ -44,6 +44,8 @@ #include <Qt3DRender/private/transform_p.h> #include <Qt3DRender/private/renderlogging_p.h> #include <Qt3DRender/private/job_common_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> #include <QThread> @@ -54,7 +56,7 @@ namespace Render { namespace { -void updateWorldTransformAndBounds(Qt3DRender::Render::Entity *node, const Matrix4x4 &parentTransform) +void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform) { Matrix4x4 worldTransform(parentTransform); Transform *nodeTransform = node->renderComponent<Transform>(); @@ -64,9 +66,12 @@ void updateWorldTransformAndBounds(Qt3DRender::Render::Entity *node, const Matri *(node->worldTransform()) = worldTransform; - const auto children = node->children(); - for (Qt3DRender::Render::Entity *child : children) - updateWorldTransformAndBounds(child, worldTransform); + const auto childrenHandles = node->childrenHandles(); + for (const HEntity &handle : childrenHandles) { + Entity *child = manager->renderNodesManager()->data(handle); + if (child) + updateWorldTransformAndBounds(manager, child, worldTransform); + } } } @@ -74,6 +79,7 @@ void updateWorldTransformAndBounds(Qt3DRender::Render::Entity *node, const Matri UpdateWorldTransformJob::UpdateWorldTransformJob() : Qt3DCore::QAspectJob() , m_node(nullptr) + , m_manager(nullptr) { SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0); } @@ -83,6 +89,11 @@ void UpdateWorldTransformJob::setRoot(Entity *root) m_node = root; } +void UpdateWorldTransformJob::setManagers(NodeManagers *manager) +{ + m_manager = manager; +} + void UpdateWorldTransformJob::run() { // Iterate over each level of hierarchy in our scene @@ -98,7 +109,7 @@ void UpdateWorldTransformJob::run() Entity *parent = m_node->parent(); if (parent != nullptr) parentTransform = *(parent->worldTransform()); - updateWorldTransformAndBounds(m_node, parentTransform); + updateWorldTransformAndBounds(m_manager, m_node, parentTransform); qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); } diff --git a/src/render/jobs/updateworldtransformjob_p.h b/src/render/jobs/updateworldtransformjob_p.h index a0ef25679..2689fe45a 100644 --- a/src/render/jobs/updateworldtransformjob_p.h +++ b/src/render/jobs/updateworldtransformjob_p.h @@ -62,6 +62,7 @@ namespace Qt3DRender { namespace Render { class Entity; +class NodeManagers; class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateWorldTransformJob : public Qt3DCore::QAspectJob { @@ -69,10 +70,13 @@ public: UpdateWorldTransformJob(); void setRoot(Entity *root); + void setManagers(NodeManagers *manager); + void run() override; private: Entity *m_node; + NodeManagers *m_manager; }; typedef QSharedPointer<UpdateWorldTransformJob> UpdateWorldTransformJobPtr; |