mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
fix Differential scan logic for LOD culling
This commit is contained in:
parent
f2de03bc38
commit
49e11d2173
4 changed files with 105 additions and 135 deletions
|
@ -106,6 +106,8 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
_sendQueue.swap(prevSendQueue);
|
||||
_entitiesInQueue.clear();
|
||||
// Re-add elements from previous traversal if they still need to be sent
|
||||
float lodScaleFactor = _traversal.getCurrentLODScaleFactor();
|
||||
glm::vec3 viewPosition = _traversal.getCurrentView().getPosition();
|
||||
while (!prevSendQueue.empty()) {
|
||||
EntityItemPointer entity = prevSendQueue.top().getEntity();
|
||||
bool forceRemove = prevSendQueue.top().shouldForceRemove();
|
||||
|
@ -118,13 +120,9 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
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 distance = (glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE);
|
||||
float apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle > MIN_ENTITY_APPARENT_ANGLE * lodScaleFactor) {
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
|
@ -144,19 +142,20 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
}
|
||||
|
||||
if (!_traversal.finished()) {
|
||||
uint64_t startTime = usecTimestampNow();
|
||||
|
||||
#ifdef DEBUG
|
||||
uint64_t startTime = usecTimestampNow();
|
||||
const uint64_t TIME_BUDGET = 400; // usec
|
||||
#else
|
||||
const uint64_t TIME_BUDGET = 200; // usec
|
||||
#endif
|
||||
_traversal.traverse(TIME_BUDGET);
|
||||
|
||||
if (_sendQueue.size() > 0) {
|
||||
uint64_t dt = usecTimestampNow() - startTime;
|
||||
std::cout << "adebug traversal complete " << " Q.size = " << _sendQueue.size() << " dt = " << dt << std::endl; // adebug
|
||||
}
|
||||
#else
|
||||
const uint64_t TIME_BUDGET = 200; // usec
|
||||
_traversal.traverse(TIME_BUDGET);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SEND_SORTED_ENTITIES
|
||||
|
@ -248,8 +247,10 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
// When we get to a First traversal, clear the _knownState
|
||||
_knownState.clear();
|
||||
if (usesViewFrustum) {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
float lodScaleFactor = _traversal.getCurrentLODScaleFactor();
|
||||
glm::vec3 viewPosition = _traversal.getCurrentView().getPosition();
|
||||
_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;
|
||||
|
@ -262,17 +263,9 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
// 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 distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle > MIN_ENTITY_APPARENT_ANGLE * lodScaleFactor) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
|
@ -285,7 +278,7 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
});
|
||||
});
|
||||
} else {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
_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()) {
|
||||
|
@ -299,28 +292,26 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
break;
|
||||
case DiffTraversal::Repeat:
|
||||
if (usesViewFrustum) {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
float lodScaleFactor = _traversal.getCurrentLODScaleFactor();
|
||||
glm::vec3 viewPosition = _traversal.getCurrentView().getPosition();
|
||||
_traversal.setScanCallback([=](DiffTraversal::VisibleElement& next) {
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
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() || entity->getLastEdited() > knownTimestamp->second) {
|
||||
if (knownTimestamp == _knownState.end()) {
|
||||
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 distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle > MIN_ENTITY_APPARENT_ANGLE * lodScaleFactor) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
|
@ -330,15 +321,20 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
} else if (entity->getLastEdited() > knownTimestamp->second) {
|
||||
// it is known and it changed --> put it on the queue with any priority
|
||||
// TODO: sort these correctly
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_traversal.setScanCallback([&](DiffTraversal::VisibleElement& next) {
|
||||
_traversal.setScanCallback([=](DiffTraversal::VisibleElement& next) {
|
||||
uint64_t startOfCompletedTraversal = _traversal.getStartOfCompletedTraversal();
|
||||
if (next.element->getLastChangedContent() > startOfCompletedTraversal) {
|
||||
next.element->forEachEntity([&](EntityItemPointer entity) {
|
||||
next.element->forEachEntity([=](EntityItemPointer entity) {
|
||||
// Bail early if we've already checked this entity this frame
|
||||
if (_entitiesInQueue.find(entity.get()) != _entitiesInQueue.end()) {
|
||||
return;
|
||||
|
@ -355,56 +351,54 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree
|
|||
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();
|
||||
if (next.intersection != ViewFrustum::INSIDE ||
|
||||
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() || entity->getLastEdited() > knownTimestamp->second) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (_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) {
|
||||
if (!_traversal.getCompletedView().cubeIntersectsKeyhole(cube)) {
|
||||
float lodScaleFactor = _traversal.getCurrentLODScaleFactor();
|
||||
glm::vec3 viewPosition = _traversal.getCurrentView().getPosition();
|
||||
float completedLODScaleFactor = _traversal.getCompletedLODScaleFactor();
|
||||
glm::vec3 completedViewPosition = _traversal.getCompletedView().getPosition();
|
||||
_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;
|
||||
}
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end()) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
|
||||
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
|
||||
float distance = glm::distance(cube.calcCenter(), viewPosition) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle > MIN_ENTITY_APPARENT_ANGLE * lodScaleFactor) {
|
||||
if (!_traversal.getCompletedView().cubeIntersectsKeyhole(cube)) {
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
} else {
|
||||
// If this entity was skipped last time because it was too small, we still need to send it
|
||||
distance = glm::distance(cube.calcCenter(), completedViewPosition) + MIN_VISIBLE_DISTANCE;
|
||||
apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle <= MIN_ENTITY_APPARENT_ANGLE * completedLODScaleFactor) {
|
||||
// this object was skipped in last completed traversal
|
||||
float priority = _conicalView.computePriority(cube);
|
||||
_sendQueue.push(PrioritizedEntity(entity, priority));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
} else {
|
||||
// If this entity was skipped last time because it was too small, we still need to send it
|
||||
renderAccuracy = calculateRenderAccuracy(_traversal.getCompletedView().getPosition(),
|
||||
cube,
|
||||
_traversal.getCompletedRootSizeScale(),
|
||||
_traversal.getCompletedLODOffset());
|
||||
|
||||
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 {
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (entity->getLastEdited() > knownTimestamp->second) {
|
||||
// it is known and it changed --> put it on the queue with any priority
|
||||
// TODO: sort these correctly
|
||||
_sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY));
|
||||
_entitiesInQueue.insert(entity.get());
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -43,12 +43,9 @@ void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::Visi
|
|||
return;
|
||||
} else if (view.viewFrustum.cubeIntersectsKeyhole(nextElement->getAACube())) {
|
||||
// check for LOD truncation
|
||||
float renderAccuracy = calculateRenderAccuracy(view.viewFrustum.getPosition(),
|
||||
nextElement->getAACube(),
|
||||
view.rootSizeScale,
|
||||
view.lodLevelOffset);
|
||||
|
||||
if (renderAccuracy > 0.0f) {
|
||||
float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = nextElement->getAACube().getScale() / distance;
|
||||
if (apparentAngle > MIN_ELEMENT_APPARENT_ANGLE * view.lodScaleFactor) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
|
@ -85,15 +82,12 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat(
|
|||
next.intersection = ViewFrustum::INSIDE;
|
||||
return;
|
||||
} else {
|
||||
ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
// check for LOD truncation
|
||||
float renderAccuracy = calculateRenderAccuracy(view.viewFrustum.getPosition(),
|
||||
nextElement->getAACube(),
|
||||
view.rootSizeScale,
|
||||
view.lodLevelOffset);
|
||||
|
||||
if (renderAccuracy > 0.0f) {
|
||||
// check for LOD truncation
|
||||
float distance = glm::distance(view.viewFrustum.getPosition(), nextElement->getAACube().calcCenter()) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = nextElement->getAACube().getScale() / distance;
|
||||
if (apparentAngle > MIN_ELEMENT_APPARENT_ANGLE * view.lodScaleFactor) {
|
||||
ViewFrustum::intersection intersection = view.viewFrustum.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = intersection;
|
||||
return;
|
||||
|
@ -125,36 +119,14 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V
|
|||
++_nextIndex;
|
||||
if (nextElement) {
|
||||
AACube cube = nextElement->getAACube();
|
||||
if (view.viewFrustum.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE) {
|
||||
// check for LOD truncation
|
||||
float renderAccuracy = calculateRenderAccuracy(view.viewFrustum.getPosition(),
|
||||
cube,
|
||||
view.rootSizeScale,
|
||||
view.lodLevelOffset);
|
||||
|
||||
if (renderAccuracy > 0.0f) {
|
||||
ViewFrustum::intersection lastIntersection = lastView.viewFrustum.calculateCubeKeyholeIntersection(cube);
|
||||
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
|
||||
next.intersection = lastIntersection;
|
||||
return;
|
||||
} 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
|
||||
renderAccuracy = calculateRenderAccuracy(lastView.viewFrustum.getPosition(),
|
||||
cube,
|
||||
lastView.rootSizeScale,
|
||||
lastView.lodLevelOffset);
|
||||
|
||||
if (renderAccuracy <= 0.0f) {
|
||||
next.element = nextElement;
|
||||
// element's intersection with lastView was effectively OUTSIDE
|
||||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// check for LOD truncation
|
||||
float distance = glm::distance(view.viewFrustum.getPosition(), cube.calcCenter()) + MIN_VISIBLE_DISTANCE;
|
||||
float apparentAngle = cube.getScale() / distance;
|
||||
if (apparentAngle > MIN_ELEMENT_APPARENT_ANGLE * view.lodScaleFactor) {
|
||||
if (view.viewFrustum.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,18 +159,20 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr
|
|||
// external code should update the _scanElementCallback after calling prepareNewTraversal
|
||||
//
|
||||
_currentView.usesViewFrustum = usesViewFrustum;
|
||||
float lodScaleFactor = powf(2.0f, lodLevelOffset);
|
||||
|
||||
Type type;
|
||||
// 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
|
||||
_currentView.rootSizeScale = root->getScale() * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT;
|
||||
_currentView.lodScaleFactor = lodScaleFactor;
|
||||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementFirstTime(next, _currentView);
|
||||
};
|
||||
} else if (!_currentView.usesViewFrustum || (_completedView.viewFrustum.isVerySimilar(viewFrustum) && lodLevelOffset == _completedView.lodLevelOffset)) {
|
||||
} else if (!_currentView.usesViewFrustum ||
|
||||
(_completedView.viewFrustum.isVerySimilar(viewFrustum) &&
|
||||
lodScaleFactor == _completedView.lodScaleFactor)) {
|
||||
type = Type::Repeat;
|
||||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementRepeat(next, _completedView, _completedView.startTime);
|
||||
|
@ -206,8 +180,7 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const ViewFrustum& viewFr
|
|||
} 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;
|
||||
_currentView.lodScaleFactor = lodScaleFactor;
|
||||
_getNextVisibleElementCallback = [&](DiffTraversal::VisibleElement& next) {
|
||||
_path.back().getNextVisibleElementDifferential(next, _currentView, _completedView);
|
||||
};
|
||||
|
|
|
@ -34,8 +34,7 @@ public:
|
|||
public:
|
||||
ViewFrustum viewFrustum;
|
||||
uint64_t startTime { 0 };
|
||||
float rootSizeScale { 1.0f };
|
||||
int32_t lodLevelOffset { 0 };
|
||||
float lodScaleFactor { 1.0f };
|
||||
bool usesViewFrustum { true };
|
||||
};
|
||||
|
||||
|
@ -66,10 +65,8 @@ public:
|
|||
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; }
|
||||
int32_t getCurrentLODOffset() const { return _currentView.lodLevelOffset; }
|
||||
int32_t getCompletedLODOffset() const { return _completedView.lodLevelOffset; }
|
||||
float getCurrentLODScaleFactor() const { return _currentView.lodScaleFactor; }
|
||||
float getCompletedLODScaleFactor() const { return _completedView.lodScaleFactor; }
|
||||
|
||||
uint64_t getStartOfCompletedTraversal() const { return _completedView.startTime; }
|
||||
bool finished() const { return _path.empty(); }
|
||||
|
|
|
@ -27,4 +27,10 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc
|
|||
|
||||
float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust);
|
||||
|
||||
const float MIN_ELEMENT_APPARENT_ANGLE = 0.0087266f; // ~0.57 degrees in radians
|
||||
// NOTE: the entity bounding cube is larger than the smallest containing octree element by sqrt(3)
|
||||
const float SQRT_THREE = 1.73205080f;
|
||||
const float MIN_ENTITY_APPARENT_ANGLE = MIN_ELEMENT_APPARENT_ANGLE * SQRT_THREE;
|
||||
const float MIN_VISIBLE_DISTANCE = 0.0001f; // helps avoid divide-by-zero check
|
||||
|
||||
#endif // hifi_OctreeUtils_h
|
||||
|
|
Loading…
Reference in a new issue