From 3e50d01734336f3c4b564848dddaae04c1f2266c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Aug 2017 09:13:50 -0700 Subject: [PATCH] more correct handling of LOD --- .../src/entities/EntityTreeSendThread.cpp | 7 ++- .../src/entities/EntityTreeSendThread.h | 2 +- libraries/entities/src/DiffTraversal.cpp | 56 +++++++++---------- libraries/entities/src/DiffTraversal.h | 15 ++--- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 031d7ac3fb..48cd8ea200 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -95,7 +95,8 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O ViewFrustum viewFrustum; nodeData->copyCurrentViewFrustum(viewFrustum); EntityTreeElementPointer root = std::dynamic_pointer_cast(_myServer->getOctree()->getRoot()); - startNewTraversal(viewFrustum, root); + int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); + startNewTraversal(viewFrustum, root, lodLevelOffset); } } if (!_traversal.finished()) { @@ -172,8 +173,8 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil return hasNewChild || hasNewDescendants; } -void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root) { - DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root); +void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset) { + DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset); // there are three types of traversal: // // (1) FirstTime = at login --> find everything in view diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 5cb2c4c76d..33c22c8c4a 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -36,7 +36,7 @@ private: bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData); - void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root); + void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset); DiffTraversal _traversal; EntityPriorityQueue _sendQueue; diff --git a/libraries/entities/src/DiffTraversal.cpp b/libraries/entities/src/DiffTraversal.cpp index fcaf2f06ee..5f105f3fb5 100644 --- a/libraries/entities/src/DiffTraversal.cpp +++ b/libraries/entities/src/DiffTraversal.cpp @@ -34,7 +34,7 @@ void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::Visi EntityTreeElementPointer element = _weakElement.lock(); if (element) { // check for LOD truncation - float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() + view.rootLevel, view.rootSizeScale); + float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() + view.lodLevelOffset, view.rootSizeScale); float distance2 = glm::distance2(view.viewFrustum.getPosition(), element->getAACube().calcCenter()); if (distance2 < visibleLimit * visibleLimit) { while (_nextIndex < NUMBER_OF_CHILDREN) { @@ -67,7 +67,7 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat( EntityTreeElementPointer element = _weakElement.lock(); if (element) { // check for LOD truncation - float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() - view.rootLevel + 1, view.rootSizeScale); + float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() + view.lodLevelOffset, view.rootSizeScale); float distance2 = glm::distance2(view.viewFrustum.getPosition(), element->getAACube().calcCenter()); if (distance2 < visibleLimit * visibleLimit) { while (_nextIndex < NUMBER_OF_CHILDREN) { @@ -95,12 +95,12 @@ DiffTraversal::DiffTraversal() { } void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::VisibleElement& next, - const DiffTraversal::View& view, const DiffTraversal::View& lastView, uint64_t lastTime) { + const DiffTraversal::View& view, const DiffTraversal::View& lastView) { if (_nextIndex == -1) { // root case is special ++_nextIndex; EntityTreeElementPointer element = _weakElement.lock(); - if (element->getLastChangedContent() > lastTime) { + if (element->getLastChangedContent() > lastView.startTime) { next.element = element; next.intersection = ViewFrustum::INTERSECT; return; @@ -110,7 +110,7 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V EntityTreeElementPointer element = _weakElement.lock(); if (element) { // check for LOD truncation - uint32_t level = element->getLevel() - view.rootLevel + 1; + int32_t level = element->getLevel() + view.lodLevelOffset; float visibleLimit = boundaryDistanceForRenderLevel(level, view.rootSizeScale); float distance2 = glm::distance2(view.viewFrustum.getPosition(), element->getAACube().calcCenter()); if (distance2 < visibleLimit * visibleLimit) { @@ -121,7 +121,7 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V AACube cube = nextElement->getAACube(); if ( view.viewFrustum.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE) { ViewFrustum::intersection lastIntersection = lastView.viewFrustum.calculateCubeKeyholeIntersection(cube); - if (!(lastIntersection == ViewFrustum::INSIDE && nextElement->getLastChanged() < lastTime)) { + if (!(lastIntersection == ViewFrustum::INSIDE && nextElement->getLastChanged() < lastView.startTime)) { next.element = nextElement; // NOTE: for differential case next.intersection is against the lastView // because this helps the "external scan" optimize its culling @@ -130,10 +130,8 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V } else { // check for LOD truncation in the last traversal because // we may need to traverse this element after all if the lastView skipped it for LOD - // - // NOTE: the element's "level" must be invariant (the differntial algorithm doesn't work otherwise) - // so we recycle the value computed higher up - visibleLimit = boundaryDistanceForRenderLevel(level, lastView.rootSizeScale); + int32_t lastLevel = element->getLevel() + lastView.lodLevelOffset; + visibleLimit = boundaryDistanceForRenderLevel(lastLevel, lastView.rootSizeScale); distance2 = glm::distance2(lastView.viewFrustum.getPosition(), element->getAACube().calcCenter()); if (distance2 >= visibleLimit * visibleLimit) { next.element = nextElement; @@ -151,7 +149,9 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V next.intersection = ViewFrustum::OUTSIDE; } -DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root) { +DiffTraversal::Type DiffTraversal::prepareNewTraversal( + const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset) { + assert(root); // there are three types of traversal: // // (1) First = fresh view --> find all elements in view @@ -167,39 +167,36 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr // external code should update the _scanElementCallback after calling prepareNewTraversal // - Type type = Type::First; - if (_startOfCompletedTraversal == 0) { - // first time + Type type; + if (_completedView.startTime == 0) { + type = Type::First; _currentView.viewFrustum = viewFrustum; + _currentView.lodLevelOffset = root->getLevel() + lodLevelOffset - 1; // -1 because true root has level=1 + _currentView.rootSizeScale = root->getScale() * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT; _getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) { _path.back().getNextVisibleElementFirstTime(next, _currentView); }; - } else if (_currentView.viewFrustum.isVerySimilar(viewFrustum)) { - // again - _getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) { - _path.back().getNextVisibleElementRepeat(next, _currentView, _startOfCompletedTraversal); - }; + } else if (_completedView.viewFrustum.isVerySimilar(viewFrustum) && lodLevelOffset == _completedView.lodLevelOffset) { type = Type::Repeat; - } else { - // differential - _currentView.viewFrustum = viewFrustum; _getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) { - _path.back().getNextVisibleElementDifferential(next, _currentView, _completedView, _startOfCompletedTraversal); + _path.back().getNextVisibleElementRepeat(next, _completedView, _completedView.startTime); }; + } else { type = Type::Differential; + _currentView.viewFrustum = viewFrustum; + _currentView.lodLevelOffset = root->getLevel() + lodLevelOffset - 1; // -1 because true root has level=1 + _currentView.rootSizeScale = root->getScale() * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT; + _getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) { + _path.back().getNextVisibleElementDifferential(next, _currentView, _completedView); + }; } - assert(root); _path.clear(); _path.push_back(DiffTraversal::Waypoint(root)); // set root fork's index such that root element returned at getNextElement() _path.back().initRootNextIndex(); - // cache LOD parameters in the _currentView - _currentView.rootLevel = root->getLevel(); - _currentView.rootSizeScale = root->getScale() * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT; - - _startOfCurrentTraversal = usecTimestampNow(); + _currentView.startTime = usecTimestampNow(); return type; } @@ -224,7 +221,6 @@ void DiffTraversal::getNextVisibleElement(DiffTraversal::VisibleElement& next) { if (_path.empty()) { // we've traversed the entire tree _completedView = _currentView; - _startOfCompletedTraversal = _startOfCurrentTraversal; return; } // keep looking for next diff --git a/libraries/entities/src/DiffTraversal.h b/libraries/entities/src/DiffTraversal.h index 53361780fc..f1025f1e3a 100644 --- a/libraries/entities/src/DiffTraversal.h +++ b/libraries/entities/src/DiffTraversal.h @@ -33,8 +33,9 @@ public: class View { public: ViewFrustum viewFrustum; + uint64_t startTime { 0 }; float rootSizeScale { 1.0f }; - float rootLevel { 0.0f }; + int32_t lodLevelOffset { 0 }; }; // Waypoint is an bookmark in a "path" of waypoints during a traversal. @@ -44,7 +45,7 @@ public: void getNextVisibleElementFirstTime(VisibleElement& next, const View& view); void getNextVisibleElementRepeat(VisibleElement& next, const View& view, uint64_t lastTime); - void getNextVisibleElementDifferential(VisibleElement& next, const View& view, const View& lastView, uint64_t lastTime); + void getNextVisibleElementDifferential(VisibleElement& next, const View& view, const View& lastView); int8_t getNextIndex() const { return _nextIndex; } void initRootNextIndex() { _nextIndex = -1; } @@ -58,12 +59,12 @@ public: DiffTraversal(); - DiffTraversal::Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root); + Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset); const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; } const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; } - uint64_t getStartOfCompletedTraversal() const { return _startOfCompletedTraversal; } + uint64_t getStartOfCompletedTraversal() const { return _completedView.startTime; } bool finished() const { return _path.empty(); } void setScanCallback(std::function cb); @@ -79,12 +80,6 @@ private: std::vector _path; std::function _getNextVisibleElementCallback { nullptr }; std::function _scanElementCallback { [](VisibleElement& e){} }; - uint64_t _startOfCompletedTraversal { 0 }; - uint64_t _startOfCurrentTraversal { 0 }; - - // LOD stuff - float _rootSizeScale { 1.0f }; - uint32_t _rootLevel { 0 }; }; #endif // hifi_EntityPriorityQueue_h