summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2019-04-03 21:20:53 +0100
committerMike Krus <mike.krus@kdab.com>2019-05-25 09:28:45 +0100
commitf6b813d900550703831798329a274113caee91c6 (patch)
tree2139254e22fab48f87617c01f6f8e18bed5659cc
parent7dcfd013e60787827fa5e31a408de04d1ed6ec0d (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.cpp44
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp255
-rw-r--r--src/render/jobs/updatelevelofdetailjob_p.h6
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;