mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
edited entities are not repeatedly sent if out of view, handles cases where usesViewFrustum changes
This commit is contained in:
parent
7938e301e7
commit
defed80be7
7 changed files with 203 additions and 182 deletions
|
@ -12,6 +12,7 @@
|
|||
#include "EntityPriorityQueue.h"
|
||||
|
||||
const float PrioritizedEntity::DO_NOT_SEND = -1.0e-6f;
|
||||
const float PrioritizedEntity::FORCE_REMOVE = -1.0e-5f;
|
||||
const float PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY = 1.0f;
|
||||
|
||||
void ConicalView::set(const ViewFrustum& viewFrustum) {
|
||||
|
|
|
@ -40,14 +40,15 @@ private:
|
|||
class PrioritizedEntity {
|
||||
public:
|
||||
static const float DO_NOT_SEND;
|
||||
static const float FORCE_REMOVE;
|
||||
static const float WHEN_IN_DOUBT_PRIORITY;
|
||||
|
||||
PrioritizedEntity(EntityItemPointer entity, float priority, bool forceSend = false) : _weakEntity(entity), _rawEntityPointer(entity.get()), _priority(priority), _forceSend(forceSend) {}
|
||||
PrioritizedEntity(EntityItemPointer entity, float priority, bool forceRemove = false) : _weakEntity(entity), _rawEntityPointer(entity.get()), _priority(priority), _forceRemove(forceRemove) {}
|
||||
float updatePriority(const ConicalView& view);
|
||||
EntityItemPointer getEntity() const { return _weakEntity.lock(); }
|
||||
EntityItem* getRawEntityPointer() const { return _rawEntityPointer; }
|
||||
float getPriority() const { return _priority; }
|
||||
bool shouldForceSend() const { return _forceSend; }
|
||||
bool shouldForceRemove() const { return _forceRemove; }
|
||||
|
||||
class Compare {
|
||||
public:
|
||||
|
@ -59,7 +60,7 @@ private:
|
|||
EntityItemWeakPointer _weakEntity;
|
||||
EntityItem* _rawEntityPointer;
|
||||
float _priority;
|
||||
bool _forceSend;
|
||||
bool _forceRemove;
|
||||
};
|
||||
|
||||
using EntityPriorityQueue = std::priority_queue< PrioritizedEntity, std::vector<PrioritizedEntity>, PrioritizedEntity::Compare >;
|
||||
|
|
|
@ -92,39 +92,39 @@ void EntityTreeSendThread::preDistributionProcessing() {
|
|||
|
||||
void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
|
||||
bool viewFrustumChanged, bool isFullScene) {
|
||||
if (nodeData->getUsesFrustum()) {
|
||||
if (viewFrustumChanged || _traversal.finished()) {
|
||||
ViewFrustum viewFrustum;
|
||||
nodeData->copyCurrentViewFrustum(viewFrustum);
|
||||
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
|
||||
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
||||
startNewTraversal(viewFrustum, root, lodLevelOffset, true);
|
||||
if (viewFrustumChanged || _traversal.finished()) {
|
||||
ViewFrustum viewFrustum;
|
||||
nodeData->copyCurrentViewFrustum(viewFrustum);
|
||||
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
|
||||
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
||||
startNewTraversal(viewFrustum, root, lodLevelOffset, nodeData->getUsesFrustum());
|
||||
|
||||
// When the viewFrustum changed the sort order may be incorrect, so we re-sort
|
||||
// and also use the opportunity to cull anything no longer in view
|
||||
if (viewFrustumChanged && !_sendQueue.empty()) {
|
||||
EntityPriorityQueue prevSendQueue;
|
||||
_sendQueue.swap(prevSendQueue);
|
||||
_entitiesInQueue.clear();
|
||||
// Re-add elements from previous traversal if they still need to be sent
|
||||
while (!prevSendQueue.empty()) {
|
||||
EntityItemPointer entity = prevSendQueue.top().getEntity();
|
||||
bool forceSend = prevSendQueue.top().shouldForceSend();
|
||||
prevSendQueue.pop();
|
||||
if (entity) {
|
||||
// When the viewFrustum changed the sort order may be incorrect, so we re-sort
|
||||
// and also use the opportunity to cull anything no longer in view
|
||||
if (viewFrustumChanged && !_sendQueue.empty()) {
|
||||
EntityPriorityQueue prevSendQueue;
|
||||
_sendQueue.swap(prevSendQueue);
|
||||
_entitiesInQueue.clear();
|
||||
// Re-add elements from previous traversal if they still need to be sent
|
||||
while (!prevSendQueue.empty()) {
|
||||
EntityItemPointer entity = prevSendQueue.top().getEntity();
|
||||
bool forceRemove = prevSendQueue.top().shouldForceRemove();
|
||||
prevSendQueue.pop();
|
||||
if (entity) {
|
||||
if (!forceRemove) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (forceSend || _traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
if (forceSend || priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
float renderAccuracy = calculateRenderAccuracy(_traversal.getCurrentView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCurrentRootSizeScale(),
|
||||
lodLevelOffset);
|
||||
|
||||
// Only send entities if they are large enough to see, or we need to update them to be out of view
|
||||
if (forceSend || renderAccuracy > 0.0f) {
|
||||
// Only send entities if they are large enough to see
|
||||
if (renderAccuracy > 0.0f) {
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
|
@ -134,15 +134,13 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
} else {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_traversal.finished()) {
|
||||
ViewFrustum viewFrustum;
|
||||
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
|
||||
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + NO_BOUNDARY_ADJUST;
|
||||
startNewTraversal(viewFrustum, root, lodLevelOffset, false);
|
||||
}
|
||||
|
||||
if (!_traversal.finished()) {
|
||||
|
@ -230,14 +228,13 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil
|
|||
return hasNewChild || hasNewDescendants;
|
||||
}
|
||||
|
||||
void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesFrustum) {
|
||||
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesFrustum);
|
||||
// there are four types of traversal:
|
||||
void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) {
|
||||
DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root, lodLevelOffset, usesViewFrustum);
|
||||
// there are three types of traversal:
|
||||
//
|
||||
// (1) FirstTime = at login --> find everything in view
|
||||
// (2) Repeat = view hasn't changed --> find what has changed since last complete traversal
|
||||
// (3) Differential = view has changed --> find what has changed or in new view but not old
|
||||
// (4) FullScene = no view frustum -> send everything
|
||||
//
|
||||
// The "scanCallback" we provide to the traversal depends on the type:
|
||||
//
|
||||
|
@ -248,83 +245,118 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
|
||||
switch (type) {
|
||||
case DiffTraversal::First:
|
||||
_traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
|
||||
// When we get to a First traversal, clear the _knownState
|
||||
_knownState.clear();
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
// Check the size of the entity, it's possible that a "too small to see" entity is included in a
|
||||
// larger octree cell because of its position (for example if it crosses the boundary of a cell it
|
||||
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
|
||||
// before we consider including it.
|
||||
//
|
||||
// TODO: compare priority against a threshold rather than bother with
|
||||
// calculateRenderAccuracy(). Would need to replace all calculateRenderAccuracy()
|
||||
// stuff everywhere with threshold in one sweep.
|
||||
float renderAccuracy = calculateRenderAccuracy(_traversal.getCurrentView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCurrentRootSizeScale(),
|
||||
_traversal.getCurrentLODOffset());
|
||||
|
||||
// Only send entities if they are large enough to see
|
||||
if (renderAccuracy > 0.0f) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
case DiffTraversal::Repeat:
|
||||
_traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
|
||||
// When we get to a First traversal, clear the _knownState
|
||||
_knownState.clear();
|
||||
if (usesViewFrustum) {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
if (_knownState.find(entity.get()) == _knownState.end() ||
|
||||
(_knownState.find(entity.get()) != _knownState.end() && entity->getLastEdited() > _knownState[entity.get()])) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (next.intersection == ViewFrustum::INSIDE || _traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
|
||||
float renderAccuracy = calculateRenderAccuracy(_traversal.getCurrentView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCurrentRootSizeScale(),
|
||||
_traversal.getCurrentLODOffset());
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
// Check the size of the entity, it's possible that a "too small to see" entity is included in a
|
||||
// larger octree cell because of its position (for example if it crosses the boundary of a cell it
|
||||
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
|
||||
// before we consider including it.
|
||||
//
|
||||
// TODO: compare priority against a threshold rather than bother with
|
||||
// calculateRenderAccuracy(). Would need to replace all calculateRenderAccuracy()
|
||||
// stuff everywhere with threshold in one sweep.
|
||||
float renderAccuracy = calculateRenderAccuracy(_traversal.getCurrentView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCurrentRootSizeScale(),
|
||||
_traversal.getCurrentLODOffset());
|
||||
|
||||
// Only send entities if they are large enough to see
|
||||
if (renderAccuracy > 0.0f) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
// Only send entities if they are large enough to see
|
||||
if (renderAccuracy > 0.0f) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case DiffTraversal::Repeat:
|
||||
if (usesViewFrustum) {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end() ||
|
||||
(knownTimestamp != _knownState.end() && entity->getLastEdited() > knownTimestamp->second)) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (next.intersection == ViewFrustum::INSIDE || _traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
|
||||
float renderAccuracy = calculateRenderAccuracy(_traversal.getCurrentView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCurrentRootSizeScale(),
|
||||
_traversal.getCurrentLODOffset());
|
||||
|
||||
// Only send entities if they are large enough to see
|
||||
if (renderAccuracy > 0.0f) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end() ||
|
||||
(knownTimestamp != _knownState.end() && entity->getLastEdited() > knownTimestamp->second)) {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case DiffTraversal::Differential:
|
||||
assert(usesViewFrustum);
|
||||
_traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
|
||||
// NOTE: for Differential case: next.intersection is against completedView not currentView
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
|
@ -335,8 +367,9 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
if (_knownState.find(entity.get()) == _knownState.end() ||
|
||||
(_knownState.find(entity.get()) != _knownState.end() && entity->getLastEdited() > _knownState[entity.get()])) {
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end() ||
|
||||
(knownTimestamp != _knownState.end() && entity->getLastEdited() > knownTimestamp->second)) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
|
@ -377,22 +410,6 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
}
|
||||
});
|
||||
break;
|
||||
case DiffTraversal::FullScene:
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
}
|
||||
if (_knownState.find(entity.get()) == _knownState.end() ||
|
||||
(_knownState.find(entity.get()) != _knownState.end() && entity->getLastEdited() > _knownState[entity.get()])) {
|
||||
// We don't have a view frustum from which to compute priority
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,7 +470,11 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
|
|||
}
|
||||
++_numEntities;
|
||||
}
|
||||
_knownState[entity.get()] = sendTime;
|
||||
if (queuedItem.shouldForceRemove()) {
|
||||
_knownState.erase(entity.get());
|
||||
} else {
|
||||
_knownState[entity.get()] = sendTime;
|
||||
}
|
||||
}
|
||||
_sendQueue.pop();
|
||||
_entitiesInQueue.erase(entity.get());
|
||||
|
@ -483,9 +504,11 @@ void EntityTreeSendThread::editingEntityPointer(const EntityItemPointer entity)
|
|||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority, true));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
// We can force a removal from _knownState if the current view is used and entity is out of view
|
||||
if (_traversal.doesCurrentUseViewFrustum() && !_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::FORCE_REMOVE, true));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
} else {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
|
|
|
@ -39,7 +39,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, int32_t lodLevelOffset, bool usesFrustum);
|
||||
void startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum);
|
||||
bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) override;
|
||||
|
||||
DiffTraversal _traversal;
|
||||
|
|
|
@ -33,18 +33,30 @@ void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::Visi
|
|||
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element) {
|
||||
// check for LOD truncation
|
||||
float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() + view.lodLevelOffset, view.rootSizeScale);
|
||||
float distance2 = glm::distance2(view.viewFrustum.getPosition(), element->getAACube().calcCenter());
|
||||
if (distance2 < visibleLimit * visibleLimit) {
|
||||
// No LOD truncation if we aren't using the view frustum
|
||||
if (!view.usesViewFrustum) {
|
||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && view.viewFrustum.cubeIntersectsKeyhole(nextElement->getAACube())) {
|
||||
if (nextElement) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check for LOD truncation
|
||||
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) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && view.viewFrustum.cubeIntersectsKeyhole(nextElement->getAACube())) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,19 +78,32 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat(
|
|||
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element) {
|
||||
// check for LOD truncation
|
||||
float visibleLimit = boundaryDistanceForRenderLevel(element->getLevel() + view.lodLevelOffset, view.rootSizeScale);
|
||||
float distance2 = glm::distance2(view.viewFrustum.getPosition(), element->getAACube().calcCenter());
|
||||
if (distance2 < visibleLimit * visibleLimit) {
|
||||
// No LOD truncation if we aren't using the view frustum
|
||||
if (!view.usesViewFrustum) {
|
||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && nextElement->getLastChanged() > lastTime) {
|
||||
ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = intersection;
|
||||
return;
|
||||
next.element = nextElement;
|
||||
next.intersection = ViewFrustum::INSIDE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check for LOD truncation
|
||||
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) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && nextElement->getLastChanged() > lastTime) {
|
||||
ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = intersection;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,45 +167,18 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V
|
|||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
}
|
||||
|
||||
void DiffTraversal::Waypoint::getNextVisibleElementFullScene(DiffTraversal::VisibleElement& next, uint64_t lastTime) {
|
||||
// NOTE: no need to set next.intersection or check LOD truncation in the "FullScene" context
|
||||
if (_nextIndex == -1) {
|
||||
++_nextIndex;
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element->getLastChangedContent() > lastTime) {
|
||||
next.element = element;
|
||||
return;
|
||||
}
|
||||
}
|
||||
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() > lastTime) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next.element.reset();
|
||||
}
|
||||
|
||||
DiffTraversal::DiffTraversal() {
|
||||
const int32_t MIN_PATH_DEPTH = 16;
|
||||
_path.reserve(MIN_PATH_DEPTH);
|
||||
}
|
||||
|
||||
DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesFrustum) {
|
||||
DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum) {
|
||||
assert(root);
|
||||
// there are four types of traversal:
|
||||
// there are three types of traversal:
|
||||
//
|
||||
// (1) First = fresh view --> find all elements in view
|
||||
// (2) Repeat = view hasn't changed --> find elements changed since last complete traversal
|
||||
// (3) Differential = view has changed --> find elements changed or in new view but not old
|
||||
// (4) FullScene = no view frustum -> send everything
|
||||
//
|
||||
// for each traversal type we assign the appropriate _getNextVisibleElementCallback
|
||||
//
|
||||
|
@ -190,14 +188,11 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr
|
|||
//
|
||||
// external code should update the _scanElementCallback after calling prepareNewTraversal
|
||||
//
|
||||
_currentView.usesViewFrustum = usesViewFrustum;
|
||||
|
||||
Type type;
|
||||
if (!usesFrustum) {
|
||||
type = Type::FullScene;
|
||||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementFullScene(next, _completedView.startTime);
|
||||
};
|
||||
} else if (_completedView.startTime == 0) {
|
||||
// If usesViewFrustum changes, treat it as a First traversal
|
||||
if (_completedView.startTime == 0 || _currentView.usesViewFrustum != _completedView.usesViewFrustum) {
|
||||
type = Type::First;
|
||||
_currentView.viewFrustum = viewFrustum;
|
||||
_currentView.lodLevelOffset = root->getLevel() + lodLevelOffset - 1; // -1 because true root has level=1
|
||||
|
@ -205,7 +200,7 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr
|
|||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementFirstTime(next, _currentView);
|
||||
};
|
||||
} else if (_completedView.viewFrustum.isVerySimilar(viewFrustum) && lodLevelOffset == _completedView.lodLevelOffset) {
|
||||
} else if (!_currentView.usesViewFrustum || (_completedView.viewFrustum.isVerySimilar(viewFrustum) && lodLevelOffset == _completedView.lodLevelOffset)) {
|
||||
type = Type::Repeat;
|
||||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementRepeat(next, _completedView, _completedView.startTime);
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
uint64_t startTime { 0 };
|
||||
float rootSizeScale { 1.0f };
|
||||
int32_t lodLevelOffset { 0 };
|
||||
bool usesViewFrustum { true };
|
||||
};
|
||||
|
||||
// Waypoint is an bookmark in a "path" of waypoints during a traversal.
|
||||
|
@ -46,7 +47,6 @@ 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);
|
||||
void getNextVisibleElementFullScene(VisibleElement& next, uint64_t lastTime);
|
||||
|
||||
int8_t getNextIndex() const { return _nextIndex; }
|
||||
void initRootNextIndex() { _nextIndex = -1; }
|
||||
|
@ -56,15 +56,16 @@ public:
|
|||
int8_t _nextIndex;
|
||||
};
|
||||
|
||||
typedef enum { First, Repeat, Differential, FullScene } Type;
|
||||
typedef enum { First, Repeat, Differential } Type;
|
||||
|
||||
DiffTraversal();
|
||||
|
||||
Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool isFullScene);
|
||||
Type prepareNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root, int32_t lodLevelOffset, bool usesViewFrustum);
|
||||
|
||||
const ViewFrustum& getCurrentView() const { return _currentView.viewFrustum; }
|
||||
const ViewFrustum& getCompletedView() const { return _completedView.viewFrustum; }
|
||||
|
||||
bool doesCurrentUseViewFrustum() const { return _currentView.usesViewFrustum; }
|
||||
float getCurrentRootSizeScale() const { return _currentView.rootSizeScale; }
|
||||
float getCompletedRootSizeScale() const { return _completedView.rootSizeScale; }
|
||||
float getCurrentLODOffset() const { return _currentView.lodLevelOffset; }
|
||||
|
|
|
@ -403,12 +403,12 @@ bool ViewFrustum::isVerySimilar(const ViewFrustum& compareTo, bool debug) const
|
|||
bool result =
|
||||
testMatches(0, positionDistance, POSITION_SIMILAR_ENOUGH) &&
|
||||
testMatches(0, angleOrientation, ORIENTATION_SIMILAR_ENOUGH) &&
|
||||
testMatches(compareTo._fieldOfView, _fieldOfView) &&
|
||||
testMatches(compareTo._aspectRatio, _aspectRatio) &&
|
||||
testMatches(compareTo._nearClip, _nearClip) &&
|
||||
testMatches(compareTo._farClip, _farClip) &&
|
||||
testMatches(compareTo._focalLength, _focalLength);
|
||||
|
||||
testMatches(compareTo._centerSphereRadius, _centerSphereRadius) &&
|
||||
testMatches(compareTo._fieldOfView, _fieldOfView) &&
|
||||
testMatches(compareTo._aspectRatio, _aspectRatio) &&
|
||||
testMatches(compareTo._nearClip, _nearClip) &&
|
||||
testMatches(compareTo._farClip, _farClip) &&
|
||||
testMatches(compareTo._focalLength, _focalLength);
|
||||
|
||||
if (!result && debug) {
|
||||
qCDebug(shared, "ViewFrustum::isVerySimilar()... result=%s\n", debug::valueOf(result));
|
||||
|
|
Loading…
Reference in a new issue