mirror of
https://github.com/overte-org/overte.git
synced 2025-08-16 09:31:57 +02:00
add basics for send queue and tree traversal
This commit is contained in:
parent
3ae5c215ba
commit
7edd99ca0b
3 changed files with 335 additions and 4 deletions
|
@ -10,12 +10,214 @@
|
|||
//
|
||||
|
||||
#include "EntityTreeSendThread.h"
|
||||
#include <iostream> // adebug
|
||||
|
||||
#include <EntityNodeData.h>
|
||||
#include <EntityTypes.h>
|
||||
|
||||
#include "EntityServer.h"
|
||||
|
||||
const float INVALID_ENTITY_SEND_PRIORITY = -1.0e-6f;
|
||||
|
||||
void PrioritizedEntity::updatePriority(const ViewFrustum& view) {
|
||||
EntityItemPointer entity = _weakEntity.lock();
|
||||
if (entity) {
|
||||
bool success;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
glm::vec3 center = cube.calcCenter() - view.getPosition();
|
||||
const float MIN_DISTANCE = 0.001f;
|
||||
float distanceToCenter = glm::length(center) + MIN_DISTANCE;
|
||||
float distance = distanceToCenter; //- 0.5f * cube.getScale();
|
||||
if (distance < MIN_DISTANCE) {
|
||||
// this object's bounding box overlaps the camera --> give it a big priority
|
||||
_priority = cube.getScale();
|
||||
} else {
|
||||
// NOTE: we assume view.aspectRatio < 1.0 (view width greater than height)
|
||||
// so we only check against the larger (horizontal) view angle
|
||||
float front = glm::dot(center, view.getDirection()) / distanceToCenter;
|
||||
if (front > cosf(view.getFieldOfView()) || distance < view.getCenterRadius()) {
|
||||
_priority = cube.getScale() / distance; // + front;
|
||||
} else {
|
||||
_priority = INVALID_ENTITY_SEND_PRIORITY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// when in doubt just it something positive
|
||||
_priority = 1.0f;
|
||||
}
|
||||
} else {
|
||||
_priority = INVALID_ENTITY_SEND_PRIORITY;
|
||||
}
|
||||
}
|
||||
|
||||
TreeTraversalPath::Fork::Fork(EntityTreeElementPointer& element) : _nextIndex(0) {
|
||||
assert(element);
|
||||
_weakElement = element;
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::Fork::getNextElement(const ViewFrustum& view) {
|
||||
if (_nextIndex == -1) {
|
||||
// only get here for the TreeTraversalPath's root Fork at the very beginning of traversal
|
||||
// safe to assume this element is in view
|
||||
++_nextIndex;
|
||||
return _weakElement.lock();
|
||||
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element) {
|
||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(view)) {
|
||||
return nextElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::Fork::getNextElementAgain(const ViewFrustum& view, uint64_t oldTime) {
|
||||
if (_nextIndex == -1) {
|
||||
// only get here for the TreeTraversalPath's root Fork at the very beginning of traversal
|
||||
// safe to assume this element is in view
|
||||
++_nextIndex;
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
assert(element); // should never lose root element
|
||||
if (element->getLastChanged() < oldTime) {
|
||||
_nextIndex = NUMBER_OF_CHILDREN;
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
if (element->getLastChanged() > oldTime) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element) {
|
||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && nextElement->getLastChanged() > oldTime &&
|
||||
ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(view)) {
|
||||
return nextElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::Fork::getNextElementDelta(const ViewFrustum& newView, const ViewFrustum& oldView, uint64_t oldTime) {
|
||||
if (_nextIndex == -1) {
|
||||
// only get here for the TreeTraversalPath's root Fork at the very beginning of traversal
|
||||
// safe to assume this element is in newView
|
||||
++_nextIndex;
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
assert(element); // should never lose root element
|
||||
if (element->getLastChanged() < oldTime) {
|
||||
_nextIndex = NUMBER_OF_CHILDREN;
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
return element;
|
||||
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element) {
|
||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement &&
|
||||
!(nextElement->getLastChanged() < oldTime &&
|
||||
ViewFrustum::INSIDE == nextElement->computeViewIntersection(oldView)) &&
|
||||
ViewFrustum::OUTSIDE != nextElement->computeViewIntersection(newView)) {
|
||||
return nextElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
|
||||
TreeTraversalPath::TreeTraversalPath() {
|
||||
const int32_t MIN_PATH_DEPTH = 16;
|
||||
_forks.reserve(MIN_PATH_DEPTH);
|
||||
_traversalCallback = std::bind(&TreeTraversalPath::traverseFirstTime, this);
|
||||
}
|
||||
|
||||
void TreeTraversalPath::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root) {
|
||||
if (_startOfLastCompletedTraversal == 0) {
|
||||
_traversalCallback = std::bind(&TreeTraversalPath::traverseFirstTime, this);
|
||||
_currentView = view;
|
||||
} else if (_currentView.isVerySimilar(view)) {
|
||||
_traversalCallback = std::bind(&TreeTraversalPath::traverseAgain, this);
|
||||
} else {
|
||||
_currentView = view;
|
||||
_traversalCallback = std::bind(&TreeTraversalPath::traverseDelta, this);
|
||||
}
|
||||
_forks.clear();
|
||||
if (root) {
|
||||
_forks.push_back(Fork(root));
|
||||
// set root fork's index such that root element returned at getNextElement()
|
||||
_forks.back().initRootNextIndex();
|
||||
}
|
||||
_startOfCurrentTraversal = usecTimestampNow();
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::traverseFirstTime() {
|
||||
return _forks.back().getNextElement(_currentView);
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::traverseAgain() {
|
||||
return _forks.back().getNextElementAgain(_currentView, _startOfLastCompletedTraversal);
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::traverseDelta() {
|
||||
return _forks.back().getNextElementDelta(_currentView, _lastCompletedView, _startOfLastCompletedTraversal);
|
||||
}
|
||||
|
||||
EntityTreeElementPointer TreeTraversalPath::getNextElement() {
|
||||
if (_forks.empty() || !_traversalCallback) {
|
||||
return EntityTreeElementPointer();
|
||||
}
|
||||
EntityTreeElementPointer nextElement = _traversalCallback();
|
||||
if (nextElement) {
|
||||
int8_t nextIndex = _forks.back().getNextIndex();
|
||||
if (nextIndex > 0) {
|
||||
// nextElement needs to be added to the path
|
||||
_forks.push_back(Fork(nextElement));
|
||||
}
|
||||
} else {
|
||||
// we're done at this level
|
||||
while (!nextElement) {
|
||||
// pop one level
|
||||
_forks.pop_back();
|
||||
if (_forks.empty()) {
|
||||
// we've traversed the entire tree
|
||||
onCompleteTraversal();
|
||||
return nextElement;
|
||||
}
|
||||
// keep looking for nextElement
|
||||
nextElement = _traversalCallback();
|
||||
if (nextElement) {
|
||||
// we've descended one level so add it to the path
|
||||
_forks.push_back(Fork(nextElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextElement;
|
||||
}
|
||||
|
||||
void TreeTraversalPath::dump() const {
|
||||
for (size_t i = 0; i < _forks.size(); ++i) {
|
||||
std::cout << (int)(_forks[i].getNextIndex()) << "-->";
|
||||
}
|
||||
}
|
||||
|
||||
void TreeTraversalPath::onCompleteTraversal() {
|
||||
_lastCompletedView = _currentView;
|
||||
_startOfLastCompletedTraversal = _startOfCurrentTraversal;
|
||||
}
|
||||
|
||||
void EntityTreeSendThread::preDistributionProcessing() {
|
||||
auto node = _node.toStrongRef();
|
||||
auto nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||
|
@ -80,8 +282,67 @@ void EntityTreeSendThread::preDistributionProcessing() {
|
|||
}
|
||||
}
|
||||
|
||||
static size_t adebug = 0;
|
||||
|
||||
void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
|
||||
bool viewFrustumChanged, bool isFullScene) {
|
||||
if (viewFrustumChanged) {
|
||||
ViewFrustum view;
|
||||
nodeData->copyCurrentViewFrustum(view);
|
||||
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
|
||||
_path.startNewTraversal(view, root);
|
||||
|
||||
std::cout << "adebug reset view" << std::endl; // adebug
|
||||
adebug = 0;
|
||||
}
|
||||
if (!_path.empty()) {
|
||||
int32_t numElements = 0;
|
||||
uint64_t t0 = usecTimestampNow();
|
||||
uint64_t now = t0;
|
||||
|
||||
QVector<EntityItemPointer> entities;
|
||||
EntityTreeElementPointer nextElement = _path.getNextElement();
|
||||
while (nextElement) {
|
||||
nextElement->getEntities(_path.getView(), entities);
|
||||
++numElements;
|
||||
|
||||
now = usecTimestampNow();
|
||||
const uint64_t PARTIAL_TRAVERSAL_TIME_BUDGET = 80;
|
||||
if (now - t0 > PARTIAL_TRAVERSAL_TIME_BUDGET) {
|
||||
break;
|
||||
}
|
||||
nextElement = _path.getNextElement();
|
||||
}
|
||||
uint64_t dt1 = now - t0;
|
||||
for (EntityItemPointer& entity : entities) {
|
||||
PrioritizedEntity entry(entity);
|
||||
entry.updatePriority(_path.getView());
|
||||
if (entry.getPriority() > INVALID_ENTITY_SEND_PRIORITY) {
|
||||
_sendQueue.push(entry);
|
||||
}
|
||||
}
|
||||
adebug += entities.size();
|
||||
std::cout << "adebug traverseTreeAndSendContents totalEntities = " << adebug
|
||||
<< " numElements = " << numElements
|
||||
<< " numEntities = " << entities.size()
|
||||
<< " dt = " << dt1 << std::endl; // adebug
|
||||
} else if (!_sendQueue.empty()) {
|
||||
|
||||
while (!_sendQueue.empty()) {
|
||||
PrioritizedEntity entry = _sendQueue.top();
|
||||
EntityItemPointer entity = entry.getEntity();
|
||||
if (entity) {
|
||||
std::cout << "adebug traverseTreeAndSendContents() " << entry.getPriority()
|
||||
<< " '" << entity->getName().toStdString() << "'"
|
||||
<< std::endl; // adebug
|
||||
}
|
||||
_sendQueue.pop();
|
||||
}
|
||||
// std::priority_queue doesn't have a clear method,
|
||||
// so we "clear" _sendQueue by setting it equal to an empty queue
|
||||
_sendQueue = EntityPriorityQueue();
|
||||
}
|
||||
|
||||
OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,79 @@
|
|||
#ifndef hifi_EntityTreeSendThread_h
|
||||
#define hifi_EntityTreeSendThread_h
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "../octree/OctreeSendThread.h"
|
||||
|
||||
#include "EntityTreeElement.h"
|
||||
|
||||
class EntityNodeData;
|
||||
class EntityItem;
|
||||
|
||||
class PrioritizedEntity {
|
||||
public:
|
||||
PrioritizedEntity(EntityItemPointer entity) : _weakEntity(entity) { }
|
||||
void updatePriority(const ViewFrustum& view);
|
||||
EntityItemPointer getEntity() const { return _weakEntity.lock(); }
|
||||
float getPriority() const { return _priority; }
|
||||
|
||||
class Compare {
|
||||
public:
|
||||
bool operator() (const PrioritizedEntity& A, const PrioritizedEntity& B) { return A._priority < B._priority; }
|
||||
};
|
||||
|
||||
friend class Compare;
|
||||
|
||||
private:
|
||||
EntityItemWeakPointer _weakEntity;
|
||||
float _priority { 0.0f };
|
||||
};
|
||||
using EntityPriorityQueue = std::priority_queue< PrioritizedEntity, std::vector<PrioritizedEntity>, PrioritizedEntity::Compare >;
|
||||
|
||||
class TreeTraversalPath {
|
||||
public:
|
||||
TreeTraversalPath();
|
||||
|
||||
void startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root);
|
||||
|
||||
EntityTreeElementPointer getNextElement();
|
||||
|
||||
const ViewFrustum& getView() const { return _currentView; }
|
||||
|
||||
bool empty() const { return _forks.empty(); }
|
||||
size_t size() const { return _forks.size(); } // adebug
|
||||
void dump() const;
|
||||
|
||||
class Fork {
|
||||
public:
|
||||
Fork(EntityTreeElementPointer& element);
|
||||
|
||||
EntityTreeElementPointer getNextElement(const ViewFrustum& view);
|
||||
EntityTreeElementPointer getNextElementAgain(const ViewFrustum& view, uint64_t oldTime);
|
||||
EntityTreeElementPointer getNextElementDelta(const ViewFrustum& newView, const ViewFrustum& oldView, uint64_t oldTime);
|
||||
int8_t getNextIndex() const { return _nextIndex; }
|
||||
void initRootNextIndex() { _nextIndex = -1; }
|
||||
|
||||
protected:
|
||||
EntityTreeElementWeakPointer _weakElement;
|
||||
int8_t _nextIndex;
|
||||
};
|
||||
|
||||
protected:
|
||||
EntityTreeElementPointer traverseFirstTime();
|
||||
EntityTreeElementPointer traverseAgain();
|
||||
EntityTreeElementPointer traverseDelta();
|
||||
void onCompleteTraversal();
|
||||
|
||||
ViewFrustum _currentView;
|
||||
ViewFrustum _lastCompletedView;
|
||||
std::vector<Fork> _forks;
|
||||
std::function<EntityTreeElementPointer()> _traversalCallback { nullptr };
|
||||
uint64_t _startOfLastCompletedTraversal { 0 };
|
||||
uint64_t _startOfCurrentTraversal { 0 };
|
||||
};
|
||||
|
||||
|
||||
class EntityTreeSendThread : public OctreeSendThread {
|
||||
|
||||
public:
|
||||
|
@ -32,6 +100,8 @@ private:
|
|||
bool addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
|
||||
bool addDescendantsToExtraFlaggedEntities(const QUuid& filteredEntityID, EntityItem& entityItem, EntityNodeData& nodeData);
|
||||
|
||||
TreeTraversalPath _path;
|
||||
EntityPriorityQueue _sendQueue;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTreeSendThread_h
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
#include "EntityItem.h"
|
||||
#include "EntityTree.h"
|
||||
|
||||
typedef QVector<EntityItemPointer> EntityItems;
|
||||
|
||||
class EntityTree;
|
||||
class EntityTreeElement;
|
||||
typedef std::shared_ptr<EntityTreeElement> EntityTreeElementPointer;
|
||||
|
||||
using EntityItems = QVector<EntityItemPointer>;
|
||||
using EntityTreeElementWeakPointer = std::weak_ptr<EntityTreeElement>;
|
||||
using EntityTreeElementPointer = std::shared_ptr<EntityTreeElement>;
|
||||
|
||||
class EntityTreeUpdateArgs {
|
||||
public:
|
||||
|
@ -173,7 +174,6 @@ public:
|
|||
void setTree(EntityTreePointer tree) { _myTree = tree; }
|
||||
EntityTreePointer getTree() const { return _myTree; }
|
||||
|
||||
bool updateEntity(const EntityItem& entity);
|
||||
void addEntityItem(EntityItemPointer entity);
|
||||
|
||||
EntityItemPointer getClosestEntity(glm::vec3 position) const;
|
||||
|
|
Loading…
Reference in a new issue