diff options
author | Mike Krus <mike.krus@kdab.com> | 2019-04-03 21:20:53 +0100 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2019-05-25 09:28:45 +0100 |
commit | f6b813d900550703831798329a274113caee91c6 (patch) | |
tree | 2139254e22fab48f87617c01f6f8e18bed5659cc | |
parent | 7dcfd013e60787827fa5e31a408de04d1ed6ec0d (diff) |
Use entity visitor to traverse scene graph
Also avoid doing traversal at all if there's no LOD components
Change-Id: I27f21f12b89bb05d8c4aecda16478261ae312c5a
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r-- | src/render/jobs/raycastingjob.cpp | 44 | ||||
-rw-r--r-- | src/render/jobs/updatelevelofdetailjob.cpp | 255 | ||||
-rw-r--r-- | src/render/jobs/updatelevelofdetailjob_p.h | 6 |
3 files changed, 156 insertions, 149 deletions
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/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; |