mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge remote-tracking branch 'hifi/master' into android_places_goto
This commit is contained in:
commit
03ca427234
44 changed files with 716 additions and 805 deletions
|
@ -548,18 +548,18 @@ void Agent::setIsAvatar(bool isAvatar) {
|
|||
if (_isAvatar && !_avatarIdentityTimer) {
|
||||
// set up the avatar timers
|
||||
_avatarIdentityTimer = new QTimer(this);
|
||||
_avatarViewTimer = new QTimer(this);
|
||||
_avatarQueryTimer = new QTimer(this);
|
||||
|
||||
// connect our slot
|
||||
connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket);
|
||||
connect(_avatarViewTimer, &QTimer::timeout, this, &Agent::sendAvatarViewFrustum);
|
||||
connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars);
|
||||
|
||||
static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
|
||||
static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000;
|
||||
|
||||
// start the timers
|
||||
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets
|
||||
_avatarViewTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS);
|
||||
_avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS);
|
||||
|
||||
// tell the avatarAudioTimer to start ticking
|
||||
QMetaObject::invokeMethod(&_avatarAudioTimer, "start");
|
||||
|
@ -572,9 +572,9 @@ void Agent::setIsAvatar(bool isAvatar) {
|
|||
delete _avatarIdentityTimer;
|
||||
_avatarIdentityTimer = nullptr;
|
||||
|
||||
_avatarViewTimer->stop();
|
||||
delete _avatarViewTimer;
|
||||
_avatarViewTimer = nullptr;
|
||||
_avatarQueryTimer->stop();
|
||||
delete _avatarQueryTimer;
|
||||
_avatarQueryTimer = nullptr;
|
||||
|
||||
// The avatar mixer never times out a connection (e.g., based on identity or data packets)
|
||||
// but rather keeps avatars in its list as long as "connected". As a result, clients timeout
|
||||
|
@ -607,20 +607,26 @@ void Agent::sendAvatarIdentityPacket() {
|
|||
}
|
||||
}
|
||||
|
||||
void Agent::sendAvatarViewFrustum() {
|
||||
void Agent::queryAvatars() {
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
|
||||
ViewFrustum view;
|
||||
view.setPosition(scriptedAvatar->getWorldPosition());
|
||||
view.setOrientation(scriptedAvatar->getHeadOrientation());
|
||||
view.calculate();
|
||||
ConicalViewFrustum conicalView { view };
|
||||
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
auto bufferStart = destinationBuffer;
|
||||
|
||||
uint8_t numFrustums = 1;
|
||||
auto viewFrustumByteArray = view.toByteArray();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
|
||||
auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size() + sizeof(numFrustums));
|
||||
avatarPacket->writePrimitive(numFrustums);
|
||||
avatarPacket->write(viewFrustumByteArray);
|
||||
destinationBuffer += conicalView.serialize(destinationBuffer);
|
||||
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket),
|
||||
{ NodeType::AvatarMixer });
|
||||
|
|
|
@ -97,7 +97,7 @@ private:
|
|||
void setAvatarSound(SharedSoundPointer avatarSound) { _avatarSound = avatarSound; }
|
||||
|
||||
void sendAvatarIdentityPacket();
|
||||
void sendAvatarViewFrustum();
|
||||
void queryAvatars();
|
||||
|
||||
QString _scriptContents;
|
||||
QTimer* _scriptRequestTimeout { nullptr };
|
||||
|
@ -107,7 +107,7 @@ private:
|
|||
int _numAvatarSoundSentBytes = 0;
|
||||
bool _isAvatar = false;
|
||||
QTimer* _avatarIdentityTimer = nullptr;
|
||||
QTimer* _avatarViewTimer = nullptr;
|
||||
QTimer* _avatarQueryTimer = nullptr;
|
||||
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
||||
|
||||
AudioGate _audioGate;
|
||||
|
|
|
@ -47,7 +47,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
|||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AvatarData, this, "queueIncomingPacket");
|
||||
packetReceiver.registerListener(PacketType::AdjustAvatarSorting, this, "handleAdjustAvatarSorting");
|
||||
packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarQuery, this, "handleAvatarQueryPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
|
||||
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||
packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket");
|
||||
|
@ -517,7 +517,7 @@ void AvatarMixer::handleAdjustAvatarSorting(QSharedPointer<ReceivedMessage> mess
|
|||
}
|
||||
|
||||
|
||||
void AvatarMixer::handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
void AvatarMixer::handleAvatarQueryPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
auto start = usecTimestampNow();
|
||||
getOrCreateClientData(senderNode);
|
||||
|
||||
|
@ -683,7 +683,7 @@ void AvatarMixer::sendStatsPacket() {
|
|||
incomingPacketStats["handleNodeIgnoreRequestPacket"] = TIGHT_LOOP_STAT_UINT64(_handleNodeIgnoreRequestPacketElapsedTime);
|
||||
incomingPacketStats["handleRadiusIgnoreRequestPacket"] = TIGHT_LOOP_STAT_UINT64(_handleRadiusIgnoreRequestPacketElapsedTime);
|
||||
incomingPacketStats["handleRequestsDomainListDataPacket"] = TIGHT_LOOP_STAT_UINT64(_handleRequestsDomainListDataPacketElapsedTime);
|
||||
incomingPacketStats["handleViewFrustumPacket"] = TIGHT_LOOP_STAT_UINT64(_handleViewFrustumPacketElapsedTime);
|
||||
incomingPacketStats["handleAvatarQueryPacket"] = TIGHT_LOOP_STAT_UINT64(_handleViewFrustumPacketElapsedTime);
|
||||
|
||||
singleCoreTasks["incoming_packets"] = incomingPacketStats;
|
||||
singleCoreTasks["sendStats"] = (float)_sendStatsElapsedTime;
|
||||
|
|
|
@ -46,7 +46,7 @@ public slots:
|
|||
private slots:
|
||||
void queueIncomingPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node);
|
||||
void handleAdjustAvatarSorting(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAvatarQueryPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
|
|
|
@ -126,17 +126,18 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self,
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::readViewFrustumPacket(QByteArray message) {
|
||||
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
|
||||
_currentViewFrustums.clear();
|
||||
|
||||
auto sourceBuffer = reinterpret_cast<const unsigned char*>(message.constData());
|
||||
|
||||
uint8_t numFrustums = 0;
|
||||
memcpy(&numFrustums, message.constData(), sizeof(numFrustums));
|
||||
message.remove(0, sizeof(numFrustums));
|
||||
memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums));
|
||||
sourceBuffer += sizeof(numFrustums);
|
||||
|
||||
for (uint8_t i = 0; i < numFrustums; ++i) {
|
||||
ViewFrustum frustum;
|
||||
auto bytesRead = frustum.fromByteArray(message);
|
||||
message.remove(0, bytesRead);
|
||||
ConicalViewFrustum frustum;
|
||||
sourceBuffer += frustum.deserialize(sourceBuffer);
|
||||
|
||||
_currentViewFrustums.push_back(frustum);
|
||||
}
|
||||
|
@ -144,8 +145,8 @@ void AvatarMixerClientData::readViewFrustumPacket(QByteArray message) {
|
|||
|
||||
bool AvatarMixerClientData::otherAvatarInView(const AABox& otherAvatarBox) {
|
||||
return std::any_of(std::begin(_currentViewFrustums), std::end(_currentViewFrustums),
|
||||
[&](const ViewFrustum& viewFrustum) {
|
||||
return viewFrustum.boxIntersectsKeyhole(otherAvatarBox);
|
||||
[&](const ConicalViewFrustum& viewFrustum) {
|
||||
return viewFrustum.intersects(otherAvatarBox);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <PortableHighResolutionClock.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <UUIDHasher.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
|
||||
const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps";
|
||||
const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
void removeFromRadiusIgnoringSet(SharedNodePointer self, const QUuid& other);
|
||||
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
|
||||
|
||||
void readViewFrustumPacket(QByteArray message);
|
||||
void readViewFrustumPacket(const QByteArray& message);
|
||||
|
||||
bool otherAvatarInView(const AABox& otherAvatarBox);
|
||||
|
||||
|
@ -110,7 +110,7 @@ public:
|
|||
bool getRequestsDomainListData() { return _requestsDomainListData; }
|
||||
void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
|
||||
|
||||
const ViewFrustums& getViewFrustums() const { return _currentViewFrustums; }
|
||||
const ConicalViewFrustums& getViewFrustums() const { return _currentViewFrustums; }
|
||||
|
||||
uint64_t getLastOtherAvatarEncodeTime(QUuid otherAvatar) const;
|
||||
void setLastOtherAvatarEncodeTime(const QUuid& otherAvatar, uint64_t time);
|
||||
|
@ -150,7 +150,7 @@ private:
|
|||
|
||||
SimpleMovingAverage _avgOtherAvatarDataRate;
|
||||
std::unordered_set<QUuid> _radiusIgnoredOthers;
|
||||
ViewFrustums _currentViewFrustums;
|
||||
ConicalViewFrustums _currentViewFrustums;
|
||||
|
||||
int _recentOtherAvatarsInView { 0 };
|
||||
int _recentOtherAvatarsOutOfView { 0 };
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
//
|
||||
// EntityPriorityQueue.cpp
|
||||
// assignment-client/src/entities
|
||||
//
|
||||
// Created by Andrew Meadows 2017.08.08
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#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 ConicalViewFrustum::set(const ViewFrustum& viewFrustum) {
|
||||
// The ConicalView has two parts: a central sphere (same as ViewFrustum) and a circular cone that bounds the frustum part.
|
||||
// Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum.
|
||||
_position = viewFrustum.getPosition();
|
||||
_direction = viewFrustum.getDirection();
|
||||
|
||||
// We cache the sin and cos of the half angle of the cone that bounds the frustum.
|
||||
// (the math here is left as an exercise for the reader)
|
||||
float A = viewFrustum.getAspectRatio();
|
||||
float t = tanf(0.5f * viewFrustum.getFieldOfView());
|
||||
_cosAngle = 1.0f / sqrtf(1.0f + (A * A + 1.0f) * (t * t));
|
||||
_sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle);
|
||||
|
||||
_radius = viewFrustum.getCenterRadius();
|
||||
}
|
||||
|
||||
float ConicalViewFrustum::computePriority(const AACube& cube) const {
|
||||
glm::vec3 p = cube.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||
float d = glm::length(p); // distance to center of bounding sphere
|
||||
float r = 0.5f * cube.getScale(); // radius of bounding sphere
|
||||
if (d < _radius + r) {
|
||||
return r;
|
||||
}
|
||||
// We check the angle between the center of the cube and the _direction of the view.
|
||||
// If it is less than the sum of the half-angle from center of cone to outer edge plus
|
||||
// the half apparent angle of the bounding sphere then it is in view.
|
||||
//
|
||||
// The math here is left as an exercise for the reader with the following hints:
|
||||
// (1) We actually check the dot product of the cube's local position rather than the angle and
|
||||
// (2) we take advantage of this trig identity: cos(A+B) = cos(A)*cos(B) - sin(A)*sin(B)
|
||||
if (glm::dot(p, _direction) > sqrtf(d * d - r * r) * _cosAngle - r * _sinAngle) {
|
||||
const float AVOID_DIVIDE_BY_ZERO = 0.001f;
|
||||
return r / (d + AVOID_DIVIDE_BY_ZERO);
|
||||
}
|
||||
return PrioritizedEntity::DO_NOT_SEND;
|
||||
}
|
||||
|
||||
|
||||
void ConicalView::set(const DiffTraversal::View& view) {
|
||||
auto size = view.viewFrustums.size();
|
||||
_conicalViewFrustums.resize(size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
_conicalViewFrustums[i].set(view.viewFrustums[i]);
|
||||
}
|
||||
}
|
||||
|
||||
float ConicalView::computePriority(const AACube& cube) const {
|
||||
if (_conicalViewFrustums.empty()) {
|
||||
return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
float priority = PrioritizedEntity::DO_NOT_SEND;
|
||||
|
||||
for (const auto& view : _conicalViewFrustums) {
|
||||
priority = std::max(priority, view.computePriority(cube));
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
|
@ -107,16 +107,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
|
||||
|
||||
DiffTraversal::View newView;
|
||||
|
||||
ViewFrustum viewFrustum;
|
||||
if (nodeData->hasMainViewFrustum()) {
|
||||
nodeData->copyCurrentMainViewFrustum(viewFrustum);
|
||||
newView.viewFrustums.push_back(viewFrustum);
|
||||
}
|
||||
if (nodeData->hasSecondaryViewFrustum()) {
|
||||
nodeData->copyCurrentSecondaryViewFrustum(viewFrustum);
|
||||
newView.viewFrustums.push_back(viewFrustum);
|
||||
}
|
||||
newView.viewFrustums = nodeData->getCurrentViews();
|
||||
|
||||
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
|
||||
newView.lodScaleFactor = powf(2.0f, lodLevelOffset);
|
||||
|
@ -141,16 +132,8 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
if (forceRemove) {
|
||||
priority = PrioritizedEntity::FORCE_REMOVE;
|
||||
} else {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
if (view.intersects(cube) && view.isBigEnough(cube)) {
|
||||
priority = _conicalView.computePriority(cube);
|
||||
}
|
||||
} else {
|
||||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
priority = view.computePriority(entity);
|
||||
}
|
||||
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
|
@ -235,11 +218,6 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
// (3) Differential = view has changed --> find what has changed or in new view but not old
|
||||
//
|
||||
// The "scanCallback" we provide to the traversal depends on the type:
|
||||
//
|
||||
// The _conicalView is updated here as a cached view approximation used by the lambdas for efficient
|
||||
// computation of entity sorting priorities.
|
||||
//
|
||||
_conicalView.set(_traversal.getCurrentView());
|
||||
|
||||
switch (type) {
|
||||
case DiffTraversal::First:
|
||||
|
@ -251,25 +229,8 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
if (_sendQueue.contains(entity.get())) {
|
||||
return;
|
||||
}
|
||||
float priority = PrioritizedEntity::DO_NOT_SEND;
|
||||
|
||||
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
// 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.
|
||||
if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
|
||||
view.isBigEnough(cube)) {
|
||||
priority = _conicalView.computePriority(cube);
|
||||
}
|
||||
} else {
|
||||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
float priority = view.computePriority(entity);
|
||||
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
_sendQueue.emplace(entity, priority);
|
||||
|
@ -288,21 +249,11 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
}
|
||||
float priority = PrioritizedEntity::DO_NOT_SEND;
|
||||
|
||||
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end()) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
|
||||
if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
|
||||
view.isBigEnough(cube)) {
|
||||
priority = _conicalView.computePriority(cube);
|
||||
}
|
||||
} else {
|
||||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
priority = view.computePriority(entity);
|
||||
|
||||
} else if (entity->getLastEdited() > knownTimestamp->second ||
|
||||
entity->getLastChangedOnServer() > knownTimestamp->second) {
|
||||
// it is known and it changed --> put it on the queue with any priority
|
||||
|
@ -310,7 +261,6 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
_sendQueue.emplace(entity, priority);
|
||||
}
|
||||
|
@ -328,21 +278,11 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
}
|
||||
float priority = PrioritizedEntity::DO_NOT_SEND;
|
||||
|
||||
|
||||
auto knownTimestamp = _knownState.find(entity.get());
|
||||
if (knownTimestamp == _knownState.end()) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
// See the DiffTraversal::First case for an explanation of the "entity is too small" check
|
||||
if ((next.intersection == ViewFrustum::INSIDE || view.intersects(cube)) &&
|
||||
view.isBigEnough(cube)) {
|
||||
priority = _conicalView.computePriority(cube);
|
||||
}
|
||||
} else {
|
||||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
priority = view.computePriority(entity);
|
||||
|
||||
} else if (entity->getLastEdited() > knownTimestamp->second ||
|
||||
entity->getLastChangedOnServer() > knownTimestamp->second) {
|
||||
// it is known and it changed --> put it on the queue with any priority
|
||||
|
@ -350,7 +290,6 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
|
|||
priority = PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
|
||||
if (priority != PrioritizedEntity::DO_NOT_SEND) {
|
||||
_sendQueue.emplace(entity, priority);
|
||||
}
|
||||
|
@ -463,14 +402,13 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
|
|||
void EntityTreeSendThread::editingEntityPointer(const EntityItemPointer& entity) {
|
||||
if (entity) {
|
||||
if (!_sendQueue.contains(entity.get()) && _knownState.find(entity.get()) != _knownState.end()) {
|
||||
bool success = false;
|
||||
AACube cube = entity->getQueryAACube(success);
|
||||
if (success) {
|
||||
// We can force a removal from _knownState if the current view is used and entity is out of view
|
||||
if (_traversal.doesCurrentUseViewFrustum() && !_traversal.getCurrentView().intersects(cube)) {
|
||||
_sendQueue.emplace(entity, PrioritizedEntity::FORCE_REMOVE, true);
|
||||
}
|
||||
} else {
|
||||
const auto& view = _traversal.getCurrentView();
|
||||
float priority = view.computePriority(entity);
|
||||
|
||||
// We can force a removal from _knownState if the current view is used and entity is out of view
|
||||
if (priority == PrioritizedEntity::DO_NOT_SEND) {
|
||||
_sendQueue.emplace(entity, PrioritizedEntity::FORCE_REMOVE, true);
|
||||
} else if (priority == PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY) {
|
||||
_sendQueue.emplace(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,9 @@
|
|||
#include "../octree/OctreeSendThread.h"
|
||||
|
||||
#include <DiffTraversal.h>
|
||||
#include <EntityPriorityQueue.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
|
||||
#include "EntityPriorityQueue.h"
|
||||
|
||||
class EntityNodeData;
|
||||
class EntityItem;
|
||||
|
@ -51,7 +52,6 @@ private:
|
|||
DiffTraversal _traversal;
|
||||
EntityPriorityQueue _sendQueue;
|
||||
std::unordered_map<EntityItem*, uint64_t> _knownState;
|
||||
ConicalView _conicalView; // cached optimized view for fast priority calculations
|
||||
|
||||
// packet construction stuff
|
||||
EntityTreeElementExtraEncodeDataPointer _extraEncodeData { new EntityTreeElementExtraEncodeData() };
|
||||
|
|
|
@ -19,7 +19,10 @@ void OctreeHeadlessViewer::queryOctree() {
|
|||
PacketType packetType = getMyQueryMessageType();
|
||||
|
||||
if (_hasViewFrustum) {
|
||||
_octreeQuery.setMainViewFrustum(_viewFrustum);
|
||||
ConicalViewFrustums views { _viewFrustum };
|
||||
_octreeQuery.setConicalViews(views);
|
||||
} else {
|
||||
_octreeQuery.clearConicalViews();
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
|
|
@ -330,7 +330,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode*
|
|||
} else {
|
||||
// we aren't forcing a full scene, check if something else suggests we should
|
||||
isFullScene = nodeData->haveJSONParametersChanged() ||
|
||||
(nodeData->hasMainViewFrustum() &&
|
||||
(nodeData->hasConicalViews() &&
|
||||
(nodeData->getViewFrustumJustStoppedChanging() ||
|
||||
nodeData->hasLodChanged()));
|
||||
}
|
||||
|
|
|
@ -47,6 +47,13 @@ Item {
|
|||
|
||||
onWalletAuthenticatedStatusResult: {
|
||||
submitPassphraseInputButton.enabled = true;
|
||||
|
||||
// It's not possible to auth with a blank passphrase,
|
||||
// so bail early if we get this signal without anything in the passphrase field
|
||||
if (passphraseField.text === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
errorText.text = "Authentication failed - please try again.";
|
||||
passphraseField.error = true;
|
||||
|
@ -211,6 +218,10 @@ Item {
|
|||
error = false;
|
||||
focus = true;
|
||||
forceActiveFocus();
|
||||
} else {
|
||||
showPassphrase.checked = false;
|
||||
passphraseField.text = "";
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -967,7 +967,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_entitySimulation(new PhysicalEntitySimulation()),
|
||||
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
|
||||
_entityClipboard(new EntityTree()),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
|
||||
|
@ -5088,7 +5087,7 @@ void Application::reloadResourceCaches() {
|
|||
resetPhysicsReadyInformation();
|
||||
|
||||
// Query the octree to refresh everything in view
|
||||
_lastQueriedTime = 0;
|
||||
_queryExpiry = SteadyClock::now();
|
||||
_octreeQuery.incrementConnectionID();
|
||||
|
||||
queryOctree(NodeType::EntityServer, PacketType::EntityQuery);
|
||||
|
@ -5233,10 +5232,10 @@ void Application::updateSecondaryCameraViewFrustum() {
|
|||
auto camera = dynamic_cast<SecondaryCameraJobConfig*>(renderConfig->getConfig("SecondaryCamera"));
|
||||
|
||||
if (!camera || !camera->isEnabled()) {
|
||||
_hasSecondaryViewFrustum = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ViewFrustum secondaryViewFrustum;
|
||||
if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId);
|
||||
|
@ -5261,36 +5260,37 @@ void Application::updateSecondaryCameraViewFrustum() {
|
|||
|
||||
// set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation
|
||||
glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation);
|
||||
_secondaryViewFrustum.setPosition(mirrorCameraPositionWorld);
|
||||
_secondaryViewFrustum.setOrientation(mirrorCameraOrientation);
|
||||
secondaryViewFrustum.setPosition(mirrorCameraPositionWorld);
|
||||
secondaryViewFrustum.setOrientation(mirrorCameraOrientation);
|
||||
|
||||
// build frustum using mirror space translation of mirrored camera
|
||||
float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f;
|
||||
glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror;
|
||||
glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror;
|
||||
glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance);
|
||||
_secondaryViewFrustum.setProjection(frustum);
|
||||
secondaryViewFrustum.setProjection(frustum);
|
||||
} else {
|
||||
if (!camera->attachedEntityId.isNull()) {
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId);
|
||||
_secondaryViewFrustum.setPosition(entityProperties.getPosition());
|
||||
_secondaryViewFrustum.setOrientation(entityProperties.getRotation());
|
||||
secondaryViewFrustum.setPosition(entityProperties.getPosition());
|
||||
secondaryViewFrustum.setOrientation(entityProperties.getRotation());
|
||||
} else {
|
||||
_secondaryViewFrustum.setPosition(camera->position);
|
||||
_secondaryViewFrustum.setOrientation(camera->orientation);
|
||||
secondaryViewFrustum.setPosition(camera->position);
|
||||
secondaryViewFrustum.setOrientation(camera->orientation);
|
||||
}
|
||||
|
||||
float aspectRatio = (float)camera->textureWidth / (float)camera->textureHeight;
|
||||
_secondaryViewFrustum.setProjection(camera->vFoV,
|
||||
secondaryViewFrustum.setProjection(camera->vFoV,
|
||||
aspectRatio,
|
||||
camera->nearClipPlaneDistance,
|
||||
camera->farClipPlaneDistance);
|
||||
}
|
||||
// Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera,
|
||||
// which is not what we want here.
|
||||
_secondaryViewFrustum.calculate();
|
||||
_hasSecondaryViewFrustum = true;
|
||||
secondaryViewFrustum.calculate();
|
||||
|
||||
_conicalViews.push_back(secondaryViewFrustum);
|
||||
}
|
||||
|
||||
static bool domainLoadingInProgress = false;
|
||||
|
@ -5647,6 +5647,8 @@ void Application::update(float deltaTime) {
|
|||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_myCamera.loadViewFrustum(_viewFrustum);
|
||||
|
||||
_conicalViews.clear();
|
||||
_conicalViews.push_back(_viewFrustum);
|
||||
// TODO: Fix this by modeling the way the secondary camera works on how the main camera works
|
||||
// ie. Use a camera object stored in the game logic and informs the Engine on where the secondary
|
||||
// camera should be.
|
||||
|
@ -5660,21 +5662,31 @@ void Application::update(float deltaTime) {
|
|||
PROFILE_RANGE_EX(app, "QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
|
||||
PerformanceTimer perfTimer("queryOctree");
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
quint64 sinceLastQuery = now - _lastQueriedTime;
|
||||
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
||||
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
||||
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
||||
viewIsDifferentEnough |= _hasSecondaryViewFrustum && !_lastQueriedSecondaryViewFrustum.isVerySimilar(_secondaryViewFrustum);
|
||||
|
||||
bool viewIsDifferentEnough = false;
|
||||
if (_conicalViews.size() == _lastQueriedViews.size()) {
|
||||
for (size_t i = 0; i < _conicalViews.size(); ++i) {
|
||||
if (!_conicalViews[i].isVerySimilar(_lastQueriedViews[i])) {
|
||||
viewIsDifferentEnough = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
viewIsDifferentEnough = true;
|
||||
}
|
||||
|
||||
|
||||
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
||||
if (queryIsDue || viewIsDifferentEnough) {
|
||||
_lastQueriedTime = now;
|
||||
static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES { 3 };
|
||||
auto now = SteadyClock::now();
|
||||
if (now > _queryExpiry || viewIsDifferentEnough) {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
queryOctree(NodeType::EntityServer, PacketType::EntityQuery);
|
||||
}
|
||||
sendAvatarViewFrustum();
|
||||
_lastQueriedViewFrustum = _viewFrustum;
|
||||
_lastQueriedSecondaryViewFrustum = _secondaryViewFrustum;
|
||||
queryAvatars();
|
||||
|
||||
_lastQueriedViews = _conicalViews;
|
||||
_queryExpiry = now + MIN_PERIOD_BETWEEN_QUERIES;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5846,18 +5858,20 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::sendAvatarViewFrustum() {
|
||||
uint8_t numFrustums = 1;
|
||||
QByteArray viewFrustumByteArray = _viewFrustum.toByteArray();
|
||||
void Application::queryAvatars() {
|
||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
|
||||
if (_hasSecondaryViewFrustum) {
|
||||
++numFrustums;
|
||||
viewFrustumByteArray += _secondaryViewFrustum.toByteArray();
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
}
|
||||
|
||||
auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size() + sizeof(numFrustums));
|
||||
avatarPacket->writePrimitive(numFrustums);
|
||||
avatarPacket->write(viewFrustumByteArray);
|
||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||
|
||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
@ -5919,16 +5933,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) {
|
|||
return; // bail early if settings are not loaded
|
||||
}
|
||||
|
||||
ViewFrustum viewFrustum;
|
||||
copyViewFrustum(viewFrustum);
|
||||
_octreeQuery.setMainViewFrustum(viewFrustum);
|
||||
|
||||
if (hasSecondaryViewFrustum()) {
|
||||
copySecondaryViewFrustum(viewFrustum);
|
||||
_octreeQuery.setSecondaryViewFrustum(viewFrustum);
|
||||
} else {
|
||||
_octreeQuery.clearSecondaryViewFrustum();
|
||||
}
|
||||
_octreeQuery.setConicalViews(_conicalViews);
|
||||
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
|
||||
|
@ -6013,11 +6018,6 @@ void Application::copyDisplayViewFrustum(ViewFrustum& viewOut) const {
|
|||
viewOut = _displayViewFrustum;
|
||||
}
|
||||
|
||||
void Application::copySecondaryViewFrustum(ViewFrustum& viewOut) const {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
viewOut = _secondaryViewFrustum;
|
||||
}
|
||||
|
||||
void Application::resetSensors(bool andReload) {
|
||||
DependencyManager::get<DdeFaceTracker>()->reset();
|
||||
DependencyManager::get<EyeTracker>()->reset();
|
||||
|
@ -6143,7 +6143,7 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
// If we get a new EntityServer activated, reset lastQueried time
|
||||
// so we will do a proper query during update
|
||||
if (node->getType() == NodeType::EntityServer) {
|
||||
_lastQueriedTime = 0;
|
||||
_queryExpiry = SteadyClock::now();
|
||||
_octreeQuery.incrementConnectionID();
|
||||
}
|
||||
|
||||
|
@ -6152,6 +6152,8 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
}
|
||||
|
||||
if (node->getType() == NodeType::AvatarMixer) {
|
||||
_queryExpiry = SteadyClock::now();
|
||||
|
||||
// new avatar mixer, send off our identity packet on next update loop
|
||||
// Reset skeletonModelUrl if the last server modified our choice.
|
||||
// Override the avatar url (but not model name) here too.
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <AbstractUriHandler.h>
|
||||
#include <shared/RateCounter.h>
|
||||
#include <ThreadSafeValueCache.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
#include <shared/FileLogger.h>
|
||||
|
||||
#include <RunningMarker.h>
|
||||
|
@ -110,7 +111,8 @@ class Application : public QApplication,
|
|||
public AbstractViewStateInterface,
|
||||
public AbstractScriptingServicesInterface,
|
||||
public AbstractUriHandler,
|
||||
public PluginContainer {
|
||||
public PluginContainer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
// TODO? Get rid of those
|
||||
|
@ -175,14 +177,14 @@ public:
|
|||
Camera& getCamera() { return _myCamera; }
|
||||
const Camera& getCamera() const { return _myCamera; }
|
||||
// Represents the current view frustum of the avatar.
|
||||
void copyViewFrustum(ViewFrustum& viewOut) const override;
|
||||
void copySecondaryViewFrustum(ViewFrustum& viewOut) const override;
|
||||
bool hasSecondaryViewFrustum() const override { return _hasSecondaryViewFrustum; }
|
||||
void copyViewFrustum(ViewFrustum& viewOut) const;
|
||||
// Represents the view frustum of the current rendering pass,
|
||||
// which might be different from the viewFrustum, i.e. shadowmap
|
||||
// passes, mirror window passes, etc
|
||||
void copyDisplayViewFrustum(ViewFrustum& viewOut) const;
|
||||
|
||||
const ConicalViewFrustums& getConicalViews() const override { return _conicalViews; }
|
||||
|
||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||
QSharedPointer<EntityTreeRenderer> getEntities() const { return DependencyManager::get<EntityTreeRenderer>(); }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
|
@ -491,9 +493,9 @@ private:
|
|||
void updateDialogs(float deltaTime) const;
|
||||
|
||||
void queryOctree(NodeType_t serverType, PacketType packetType);
|
||||
void queryAvatars();
|
||||
|
||||
int sendNackPackets();
|
||||
void sendAvatarViewFrustum();
|
||||
|
||||
std::shared_ptr<MyAvatar> getMyAvatar() const;
|
||||
|
||||
|
@ -574,12 +576,14 @@ private:
|
|||
|
||||
mutable QMutex _viewMutex { QMutex::Recursive };
|
||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
ViewFrustum _lastQueriedViewFrustum; // last view frustum used to query octree servers
|
||||
ViewFrustum _displayViewFrustum;
|
||||
ViewFrustum _secondaryViewFrustum;
|
||||
ViewFrustum _lastQueriedSecondaryViewFrustum; // last secondary view frustum used to query octree servers
|
||||
bool _hasSecondaryViewFrustum;
|
||||
quint64 _lastQueriedTime;
|
||||
|
||||
ConicalViewFrustums _conicalViews;
|
||||
ConicalViewFrustums _lastQueriedViews; // last views used to query servers
|
||||
|
||||
using SteadyClock = std::chrono::steady_clock;
|
||||
using TimePoint = SteadyClock::time_point;
|
||||
TimePoint _queryExpiry;
|
||||
|
||||
OctreeQuery _octreeQuery { true }; // NodeData derived class for querying octee cells from octree servers
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <UsersScriptingInterface.h>
|
||||
#include <UUID.h>
|
||||
#include <avatars-renderer/OtherAvatar.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "AvatarManager.h"
|
||||
|
@ -156,17 +157,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
};
|
||||
|
||||
|
||||
ViewFrustums views;
|
||||
|
||||
ViewFrustum view;
|
||||
qApp->copyCurrentViewFrustum(view);
|
||||
views.push_back(view);
|
||||
|
||||
if (qApp->hasSecondaryViewFrustum()) {
|
||||
qApp->copySecondaryViewFrustum(view);
|
||||
views.push_back(view);
|
||||
}
|
||||
|
||||
const auto& views = qApp->getConicalViews();
|
||||
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(views,
|
||||
AvatarData::_avatarSortCoefficientSize,
|
||||
AvatarData::_avatarSortCoefficientCenter,
|
||||
|
|
|
@ -296,8 +296,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, const ViewFrustums& views,
|
||||
render::Transaction& transaction) {
|
||||
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
PROFILE_RANGE_EX(simulation_physics, "ChangeInScene", 0xffff00ff, (uint64_t)_changedEntities.size());
|
||||
PerformanceTimer pt("change");
|
||||
std::unordered_set<EntityItemID> changedEntities;
|
||||
|
@ -358,6 +357,8 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
|||
|
||||
// prioritize and sort the renderables
|
||||
uint64_t sortStart = usecTimestampNow();
|
||||
|
||||
const auto& views = _viewState->getConicalViews();
|
||||
PrioritySortUtil::PriorityQueue<SortableRenderer> sortedRenderables(views);
|
||||
{
|
||||
PROFILE_RANGE_EX(simulation_physics, "SortRenderables", 0xffff00ff, (uint64_t)_renderablesToUpdate.size());
|
||||
|
@ -417,19 +418,7 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
render::Transaction transaction;
|
||||
addPendingEntities(scene, transaction);
|
||||
|
||||
ViewFrustums views;
|
||||
|
||||
ViewFrustum view;
|
||||
_viewState->copyViewFrustum(view);
|
||||
views.push_back(view);
|
||||
|
||||
if (_viewState->hasSecondaryViewFrustum()) {
|
||||
_viewState->copySecondaryViewFrustum(view);
|
||||
views.push_back(view);
|
||||
}
|
||||
|
||||
|
||||
updateChangedEntities(scene, views, transaction);
|
||||
updateChangedEntities(scene, transaction);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,8 +148,7 @@ protected:
|
|||
|
||||
private:
|
||||
void addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction);
|
||||
void updateChangedEntities(const render::ScenePointer& scene, const ViewFrustums& views,
|
||||
render::Transaction& transaction);
|
||||
void updateChangedEntities(const render::ScenePointer& scene, render::Transaction& transaction);
|
||||
EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); }
|
||||
render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); }
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <OctreeUtils.h>
|
||||
|
||||
#include "EntityPriorityQueue.h"
|
||||
|
||||
DiffTraversal::Waypoint::Waypoint(EntityTreeElementPointer& element) : _nextIndex(0) {
|
||||
assert(element);
|
||||
_weakElement = element;
|
||||
|
@ -35,19 +37,9 @@ void DiffTraversal::Waypoint::getNextVisibleElementFirstTime(DiffTraversal::Visi
|
|||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement) {
|
||||
const auto& cube = nextElement->getAACube();
|
||||
if (!view.usesViewFrustums()) {
|
||||
// No LOD truncation if we aren't using the view frustum
|
||||
next.element = nextElement;
|
||||
return;
|
||||
} else if (view.intersects(cube)) {
|
||||
// check for LOD truncation
|
||||
if (view.isBigEnough(cube, MIN_ELEMENT_ANGULAR_DIAMETER)) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (nextElement && view.shouldTraverseElement(*nextElement)) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +55,6 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat(
|
|||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
if (element->getLastChangedContent() > lastTime) {
|
||||
next.element = element;
|
||||
next.intersection = ViewFrustum::INTERSECT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -73,30 +64,17 @@ void DiffTraversal::Waypoint::getNextVisibleElementRepeat(
|
|||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement && nextElement->getLastChanged() > lastTime) {
|
||||
if (!view.usesViewFrustums()) {
|
||||
// No LOD truncation if we aren't using the view frustum
|
||||
next.element = nextElement;
|
||||
next.intersection = ViewFrustum::INSIDE;
|
||||
return;
|
||||
} else {
|
||||
// check for LOD truncation
|
||||
const auto& cube = nextElement->getAACube();
|
||||
if (view.isBigEnough(cube, MIN_ELEMENT_ANGULAR_DIAMETER)) {
|
||||
ViewFrustum::intersection intersection = view.calculateIntersection(cube);
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = intersection;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextElement &&
|
||||
nextElement->getLastChanged() > lastTime &&
|
||||
view.shouldTraverseElement(*nextElement)) {
|
||||
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next.element.reset();
|
||||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
}
|
||||
|
||||
void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::VisibleElement& next,
|
||||
|
@ -106,7 +84,6 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V
|
|||
++_nextIndex;
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
next.element = element;
|
||||
next.intersection = ViewFrustum::INTERSECT;
|
||||
return;
|
||||
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer element = _weakElement.lock();
|
||||
|
@ -114,74 +91,14 @@ void DiffTraversal::Waypoint::getNextVisibleElementDifferential(DiffTraversal::V
|
|||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||
++_nextIndex;
|
||||
if (nextElement) {
|
||||
// check for LOD truncation
|
||||
const auto& cube = nextElement->getAACube();
|
||||
if (view.isBigEnough(cube, MIN_ELEMENT_ANGULAR_DIAMETER)) {
|
||||
ViewFrustum::intersection intersection = view.calculateIntersection(cube);
|
||||
if (intersection != ViewFrustum::OUTSIDE) {
|
||||
next.element = nextElement;
|
||||
next.intersection = intersection;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (nextElement && view.shouldTraverseElement(*nextElement)) {
|
||||
next.element = nextElement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next.element.reset();
|
||||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
}
|
||||
|
||||
bool DiffTraversal::View::isBigEnough(const AACube& cube, float minDiameter) const {
|
||||
if (viewFrustums.empty()) {
|
||||
// Everything is big enough when not using view frustums
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isBigEnough = std::any_of(std::begin(viewFrustums), std::end(viewFrustums),
|
||||
[&](const ViewFrustum& viewFrustum) {
|
||||
return isAngularSizeBigEnough(viewFrustum.getPosition(), cube, lodScaleFactor, minDiameter);
|
||||
});
|
||||
|
||||
return isBigEnough;
|
||||
}
|
||||
|
||||
bool DiffTraversal::View::intersects(const AACube& cube) const {
|
||||
if (viewFrustums.empty()) {
|
||||
// Everything intersects when not using view frustums
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intersects = std::any_of(std::begin(viewFrustums), std::end(viewFrustums),
|
||||
[&](const ViewFrustum& viewFrustum) {
|
||||
return viewFrustum.cubeIntersectsKeyhole(cube);
|
||||
});
|
||||
|
||||
return intersects;
|
||||
}
|
||||
|
||||
ViewFrustum::intersection DiffTraversal::View::calculateIntersection(const AACube& cube) const {
|
||||
if (viewFrustums.empty()) {
|
||||
// Everything is inside when not using view frustums
|
||||
return ViewFrustum::INSIDE;
|
||||
}
|
||||
|
||||
ViewFrustum::intersection intersection = ViewFrustum::OUTSIDE;
|
||||
|
||||
for (const auto& viewFrustum : viewFrustums) {
|
||||
switch (viewFrustum.calculateCubeKeyholeIntersection(cube)) {
|
||||
case ViewFrustum::INSIDE:
|
||||
return ViewFrustum::INSIDE;
|
||||
case ViewFrustum::INTERSECT:
|
||||
intersection = ViewFrustum::INTERSECT;
|
||||
break;
|
||||
default:
|
||||
// DO NOTHING
|
||||
break;
|
||||
}
|
||||
}
|
||||
return intersection;
|
||||
}
|
||||
|
||||
bool DiffTraversal::View::usesViewFrustums() const {
|
||||
|
@ -204,6 +121,73 @@ bool DiffTraversal::View::isVerySimilar(const View& view) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
float DiffTraversal::View::computePriority(const EntityItemPointer& entity) const {
|
||||
if (!entity) {
|
||||
return PrioritizedEntity::DO_NOT_SEND;
|
||||
}
|
||||
|
||||
if (!usesViewFrustums()) {
|
||||
return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
auto cube = entity->getQueryAACube(success);
|
||||
if (!success) {
|
||||
return PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY;
|
||||
}
|
||||
|
||||
auto center = cube.calcCenter(); // center of bounding sphere
|
||||
auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere
|
||||
|
||||
auto priority = PrioritizedEntity::DO_NOT_SEND;
|
||||
|
||||
for (const auto& frustum : viewFrustums) {
|
||||
auto position = center - frustum.getPosition(); // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position); // distance to center of bounding sphere
|
||||
|
||||
// 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.
|
||||
float angularSize = frustum.getAngularSize(distance, radius);
|
||||
if (angularSize > lodScaleFactor * MIN_ENTITY_ANGULAR_DIAMETER &&
|
||||
frustum.intersects(position, distance, radius)) {
|
||||
|
||||
// use the angular size as priority
|
||||
// we compute the max priority for all frustums
|
||||
priority = std::max(priority, angularSize);
|
||||
}
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
bool DiffTraversal::View::shouldTraverseElement(const EntityTreeElement& element) const {
|
||||
if (!usesViewFrustums()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& cube = element.getAACube();
|
||||
|
||||
auto center = cube.calcCenter(); // center of bounding sphere
|
||||
auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere
|
||||
|
||||
|
||||
return any_of(begin(viewFrustums), end(viewFrustums), [&](const ConicalViewFrustum& frustum) {
|
||||
auto position = center - frustum.getPosition(); // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position); // distance to center of bounding sphere
|
||||
|
||||
// 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.
|
||||
float angularSize = frustum.getAngularSize(distance, radius);
|
||||
|
||||
return angularSize > lodScaleFactor * MIN_ELEMENT_ANGULAR_DIAMETER &&
|
||||
frustum.intersects(position, distance, radius);
|
||||
});
|
||||
}
|
||||
|
||||
DiffTraversal::DiffTraversal() {
|
||||
const int32_t MIN_PATH_DEPTH = 16;
|
||||
_path.reserve(MIN_PATH_DEPTH);
|
||||
|
@ -262,7 +246,6 @@ DiffTraversal::Type DiffTraversal::prepareNewTraversal(const DiffTraversal::View
|
|||
void DiffTraversal::getNextVisibleElement(DiffTraversal::VisibleElement& next) {
|
||||
if (_path.empty()) {
|
||||
next.element.reset();
|
||||
next.intersection = ViewFrustum::OUTSIDE;
|
||||
return;
|
||||
}
|
||||
_getNextVisibleElementCallback(next);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef hifi_DiffTraversal_h
|
||||
#define hifi_DiffTraversal_h
|
||||
|
||||
#include <ViewFrustum.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
|
||||
#include "EntityTreeElement.h"
|
||||
|
||||
|
@ -24,19 +24,18 @@ public:
|
|||
class VisibleElement {
|
||||
public:
|
||||
EntityTreeElementPointer element;
|
||||
ViewFrustum::intersection intersection { ViewFrustum::OUTSIDE };
|
||||
};
|
||||
|
||||
// View is a struct with a ViewFrustum and LOD parameters
|
||||
class View {
|
||||
public:
|
||||
bool isBigEnough(const AACube& cube, float minDiameter = MIN_ENTITY_ANGULAR_DIAMETER) const;
|
||||
bool intersects(const AACube& cube) const;
|
||||
bool usesViewFrustums() const;
|
||||
bool isVerySimilar(const View& view) const;
|
||||
ViewFrustum::intersection calculateIntersection(const AACube& cube) const;
|
||||
|
||||
ViewFrustums viewFrustums;
|
||||
bool shouldTraverseElement(const EntityTreeElement& element) const;
|
||||
float computePriority(const EntityItemPointer& entity) const;
|
||||
|
||||
ConicalViewFrustums viewFrustums;
|
||||
uint64_t startTime { 0 };
|
||||
float lodScaleFactor { 1.0f };
|
||||
};
|
||||
|
@ -65,9 +64,6 @@ public:
|
|||
Type prepareNewTraversal(const DiffTraversal::View& view, EntityTreeElementPointer root);
|
||||
|
||||
const View& getCurrentView() const { return _currentView; }
|
||||
const View& getCompletedView() const { return _completedView; }
|
||||
|
||||
bool doesCurrentUseViewFrustum() const { return _currentView.usesViewFrustums(); }
|
||||
|
||||
uint64_t getStartOfCompletedTraversal() const { return _completedView.startTime; }
|
||||
bool finished() const { return _path.empty(); }
|
||||
|
|
|
@ -15,44 +15,14 @@
|
|||
#include <queue>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <AACube.h>
|
||||
#include <DiffTraversal.h>
|
||||
#include <EntityTreeElement.h>
|
||||
|
||||
const float SQRT_TWO_OVER_TWO = 0.7071067811865f;
|
||||
const float DEFAULT_VIEW_RADIUS = 10.0f;
|
||||
|
||||
// ConicalViewFrustum is an approximation of a ViewFrustum for fast calculation of sort priority.
|
||||
class ConicalViewFrustum {
|
||||
public:
|
||||
ConicalViewFrustum() {}
|
||||
ConicalViewFrustum(const ViewFrustum& viewFrustum) { set(viewFrustum); }
|
||||
void set(const ViewFrustum& viewFrustum);
|
||||
float computePriority(const AACube& cube) const;
|
||||
private:
|
||||
glm::vec3 _position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 _direction { 0.0f, 0.0f, 1.0f };
|
||||
float _sinAngle { SQRT_TWO_OVER_TWO };
|
||||
float _cosAngle { SQRT_TWO_OVER_TWO };
|
||||
float _radius { DEFAULT_VIEW_RADIUS };
|
||||
};
|
||||
|
||||
// Simple wrapper around a set of conical view frustums
|
||||
class ConicalView {
|
||||
public:
|
||||
ConicalView() {}
|
||||
void set(const DiffTraversal::View& view);
|
||||
float computePriority(const AACube& cube) const;
|
||||
private:
|
||||
std::vector<ConicalViewFrustum> _conicalViewFrustums;
|
||||
};
|
||||
#include "EntityItem.h"
|
||||
|
||||
// PrioritizedEntity is a placeholder in a sorted queue.
|
||||
class PrioritizedEntity {
|
||||
public:
|
||||
static const float DO_NOT_SEND;
|
||||
static const float FORCE_REMOVE;
|
||||
static const float WHEN_IN_DOUBT_PRIORITY;
|
||||
static constexpr float DO_NOT_SEND { -1.0e6f };
|
||||
static constexpr float FORCE_REMOVE { -1.0e5f };
|
||||
static constexpr float WHEN_IN_DOUBT_PRIORITY { 1.0f };
|
||||
|
||||
PrioritizedEntity(EntityItemPointer entity, float priority, bool forceRemove = false) : _weakEntity(entity), _rawEntityPointer(entity.get()), _priority(priority), _forceRemove(forceRemove) {}
|
||||
EntityItemPointer getEntity() const { return _weakEntity.lock(); }
|
|
@ -34,7 +34,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::MaterialData);
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::MultiFrustumQuery);
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentity:
|
||||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
|
@ -90,8 +90,8 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
return 18; // replace min_avatar_scale and max_avatar_scale with min_avatar_height and max_avatar_height
|
||||
case PacketType::Ping:
|
||||
return static_cast<PacketVersion>(PingVersion::IncludeConnectionID);
|
||||
case PacketType::ViewFrustum:
|
||||
return static_cast<PacketVersion>(ViewFrustumVersion::SendMultipleFrustums);
|
||||
case PacketType::AvatarQuery:
|
||||
return static_cast<PacketVersion>(AvatarQueryVersion::ConicalFrustums);
|
||||
default:
|
||||
return 20;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public:
|
|||
RadiusIgnoreRequest,
|
||||
UsernameFromIDRequest,
|
||||
UsernameFromIDReply,
|
||||
ViewFrustum,
|
||||
AvatarQuery,
|
||||
RequestsDomainListData,
|
||||
PerAvatarGainSet,
|
||||
EntityScriptGetStatus,
|
||||
|
@ -245,7 +245,8 @@ enum class EntityQueryPacketVersion: PacketVersion {
|
|||
JSONFilterWithFamilyTree = 19,
|
||||
ConnectionIdentifier = 20,
|
||||
RemovedJurisdictions = 21,
|
||||
MultiFrustumQuery = 22
|
||||
MultiFrustumQuery = 22,
|
||||
ConicalFrustums = 23
|
||||
};
|
||||
|
||||
enum class AssetServerPacketVersion: PacketVersion {
|
||||
|
@ -328,8 +329,9 @@ enum class PingVersion : PacketVersion {
|
|||
IncludeConnectionID = 18
|
||||
};
|
||||
|
||||
enum class ViewFrustumVersion : PacketVersion {
|
||||
SendMultipleFrustums = 21
|
||||
enum class AvatarQueryVersion : PacketVersion {
|
||||
SendMultipleFrustums = 21,
|
||||
ConicalFrustums = 22
|
||||
};
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
||||
using QueryFlags = uint8_t;
|
||||
const QueryFlags QUERY_HAS_MAIN_FRUSTUM = 1U << 0;
|
||||
const QueryFlags QUERY_HAS_SECONDARY_FRUSTUM = 1U << 1;
|
||||
|
||||
OctreeQuery::OctreeQuery(bool randomizeConnectionID) {
|
||||
if (randomizeConnectionID) {
|
||||
// randomize our initial octree query connection ID using random_device
|
||||
|
@ -38,27 +34,13 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
memcpy(destinationBuffer, &_connectionID, sizeof(_connectionID));
|
||||
destinationBuffer += sizeof(_connectionID);
|
||||
|
||||
// flags for wether the frustums are present
|
||||
QueryFlags frustumFlags = 0;
|
||||
if (_hasMainFrustum) {
|
||||
frustumFlags |= QUERY_HAS_MAIN_FRUSTUM;
|
||||
}
|
||||
if (_hasSecondaryFrustum) {
|
||||
frustumFlags |= QUERY_HAS_SECONDARY_FRUSTUM;
|
||||
}
|
||||
memcpy(destinationBuffer, &frustumFlags, sizeof(frustumFlags));
|
||||
destinationBuffer += sizeof(frustumFlags);
|
||||
// Number of frustums
|
||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||
destinationBuffer += sizeof(numFrustums);
|
||||
|
||||
if (_hasMainFrustum) {
|
||||
auto byteArray = _mainViewFrustum.toByteArray();
|
||||
memcpy(destinationBuffer, byteArray.constData(), byteArray.size());
|
||||
destinationBuffer += byteArray.size();
|
||||
}
|
||||
|
||||
if (_hasSecondaryFrustum) {
|
||||
auto byteArray = _secondaryViewFrustum.toByteArray();
|
||||
memcpy(destinationBuffer, byteArray.constData(), byteArray.size());
|
||||
destinationBuffer += byteArray.size();
|
||||
for (const auto& view : _conicalViews) {
|
||||
destinationBuffer += view.serialize(destinationBuffer);
|
||||
}
|
||||
|
||||
// desired Max Octree PPS
|
||||
|
@ -99,7 +81,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
int OctreeQuery::parseData(ReceivedMessage& message) {
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(message.getRawMessage());
|
||||
const unsigned char* endPosition = startPosition + message.getSize();
|
||||
const unsigned char* sourceBuffer = startPosition;
|
||||
|
||||
// unpack the connection ID
|
||||
|
@ -123,23 +104,15 @@ int OctreeQuery::parseData(ReceivedMessage& message) {
|
|||
}
|
||||
|
||||
// check if this query uses a view frustum
|
||||
QueryFlags frustumFlags { 0 };
|
||||
memcpy(&frustumFlags, sourceBuffer, sizeof(frustumFlags));
|
||||
sourceBuffer += sizeof(frustumFlags);
|
||||
uint8_t numFrustums = 0;
|
||||
memcpy(&numFrustums, sourceBuffer, sizeof(numFrustums));
|
||||
sourceBuffer += sizeof(numFrustums);
|
||||
|
||||
_hasMainFrustum = frustumFlags & QUERY_HAS_MAIN_FRUSTUM;
|
||||
_hasSecondaryFrustum = frustumFlags & QUERY_HAS_SECONDARY_FRUSTUM;
|
||||
|
||||
if (_hasMainFrustum) {
|
||||
auto bytesLeft = endPosition - sourceBuffer;
|
||||
auto byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(sourceBuffer), bytesLeft);
|
||||
sourceBuffer += _mainViewFrustum.fromByteArray(byteArray);
|
||||
}
|
||||
|
||||
if (_hasSecondaryFrustum) {
|
||||
auto bytesLeft = endPosition - sourceBuffer;
|
||||
auto byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(sourceBuffer), bytesLeft);
|
||||
sourceBuffer += _secondaryViewFrustum.fromByteArray(byteArray);
|
||||
_conicalViews.clear();
|
||||
for (int i = 0; i < numFrustums; ++i) {
|
||||
ConicalViewFrustum view;
|
||||
sourceBuffer += view.deserialize(sourceBuffer);
|
||||
_conicalViews.push_back(view);
|
||||
}
|
||||
|
||||
// desired Max Octree PPS
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <QtCore/QReadWriteLock>
|
||||
|
||||
#include <NodeData.h>
|
||||
|
||||
#include <ViewFrustum.h>
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
|
||||
#include "OctreeConstants.h"
|
||||
|
||||
|
@ -34,15 +33,9 @@ public:
|
|||
int getBroadcastData(unsigned char* destinationBuffer);
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
|
||||
bool hasMainViewFrustum() const { return _hasMainFrustum; }
|
||||
void setMainViewFrustum(const ViewFrustum& viewFrustum) { _hasMainFrustum = true; _mainViewFrustum = viewFrustum; }
|
||||
void clearMainViewFrustum() { _hasMainFrustum = false; }
|
||||
const ViewFrustum& getMainViewFrustum() const { return _mainViewFrustum; }
|
||||
|
||||
bool hasSecondaryViewFrustum() const { return _hasSecondaryFrustum; }
|
||||
void setSecondaryViewFrustum(const ViewFrustum& viewFrustum) { _hasSecondaryFrustum = true; _secondaryViewFrustum = viewFrustum; }
|
||||
void clearSecondaryViewFrustum() { _hasSecondaryFrustum = false; }
|
||||
const ViewFrustum& getSecondaryViewFrustum() const { return _secondaryViewFrustum; }
|
||||
bool hasConicalViews() const { return !_conicalViews.empty(); }
|
||||
void setConicalViews(ConicalViewFrustums views) { _conicalViews = views; }
|
||||
void clearConicalViews() { _conicalViews.clear(); }
|
||||
|
||||
// getters/setters for JSON filter
|
||||
QJsonObject getJSONParameters() { QReadLocker locker { &_jsonParametersLock }; return _jsonParameters; }
|
||||
|
@ -67,10 +60,7 @@ public slots:
|
|||
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; }
|
||||
|
||||
protected:
|
||||
bool _hasMainFrustum { false };
|
||||
ViewFrustum _mainViewFrustum;
|
||||
bool _hasSecondaryFrustum { false };
|
||||
ViewFrustum _secondaryViewFrustum;
|
||||
ConicalViewFrustums _conicalViews;
|
||||
|
||||
// octree server sending items
|
||||
int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS;
|
||||
|
|
|
@ -139,23 +139,13 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, unsigned int by
|
|||
}
|
||||
}
|
||||
|
||||
void OctreeQueryNode::copyCurrentMainViewFrustum(ViewFrustum& viewOut) const {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
viewOut = _currentMainViewFrustum;
|
||||
}
|
||||
|
||||
void OctreeQueryNode::copyCurrentSecondaryViewFrustum(ViewFrustum& viewOut) const {
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
viewOut = _currentSecondaryViewFrustum;
|
||||
}
|
||||
|
||||
bool OctreeQueryNode::updateCurrentViewFrustum() {
|
||||
// if shutting down, return immediately
|
||||
if (_isShuttingDown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_hasMainFrustum && !_hasSecondaryFrustum) {
|
||||
if (!hasConicalViews()) {
|
||||
// this client does not use a view frustum so the view frustum for this query has not changed
|
||||
return false;
|
||||
}
|
||||
|
@ -164,12 +154,17 @@ bool OctreeQueryNode::updateCurrentViewFrustum() {
|
|||
|
||||
{ // if there has been a change, then recalculate
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
if (_hasMainFrustum && !_mainViewFrustum.isVerySimilar(_currentMainViewFrustum)) {
|
||||
_currentMainViewFrustum = _mainViewFrustum;
|
||||
currentViewFrustumChanged = true;
|
||||
}
|
||||
if (_hasSecondaryFrustum && !_secondaryViewFrustum.isVerySimilar(_currentSecondaryViewFrustum)) {
|
||||
_currentSecondaryViewFrustum = _secondaryViewFrustum;
|
||||
|
||||
if (_conicalViews.size() == _currentConicalViews.size()) {
|
||||
for (size_t i = 0; i < _conicalViews.size(); ++i) {
|
||||
if (!_conicalViews[i].isVerySimilar(_currentConicalViews[i])) {
|
||||
_currentConicalViews = _conicalViews;
|
||||
currentViewFrustumChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_currentConicalViews = _conicalViews;
|
||||
currentViewFrustumChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <NodeData.h>
|
||||
#include <qqueue.h>
|
||||
|
||||
#include "OctreeConstants.h"
|
||||
#include "OctreeElementBag.h"
|
||||
#include "OctreePacketData.h"
|
||||
#include "OctreeQuery.h"
|
||||
#include "OctreeSceneStats.h"
|
||||
#include "SentPacketHistory.h"
|
||||
#include <qqueue.h>
|
||||
|
||||
class OctreeSendThread;
|
||||
class OctreeServer;
|
||||
|
@ -49,8 +49,7 @@ public:
|
|||
|
||||
OctreeElementExtraEncodeData extraEncodeData;
|
||||
|
||||
void copyCurrentMainViewFrustum(ViewFrustum& viewOut) const;
|
||||
void copyCurrentSecondaryViewFrustum(ViewFrustum& viewOut) const;
|
||||
const ConicalViewFrustums& getCurrentViews() const { return _currentConicalViews; }
|
||||
|
||||
// These are not classic setters because they are calculating and maintaining state
|
||||
// which is set asynchronously through the network receive
|
||||
|
@ -97,8 +96,7 @@ private:
|
|||
quint64 _firstSuppressedPacket { usecTimestampNow() };
|
||||
|
||||
mutable QMutex _viewMutex { QMutex::Recursive };
|
||||
ViewFrustum _currentMainViewFrustum;
|
||||
ViewFrustum _currentSecondaryViewFrustum;
|
||||
ConicalViewFrustums _currentConicalViews;
|
||||
bool _viewFrustumChanging { false };
|
||||
bool _viewFrustumJustStoppedChanging { true };
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_OctreeUtils_h
|
||||
#define hifi_OctreeUtils_h
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "OctreeConstants.h"
|
||||
|
||||
class AABox;
|
||||
|
@ -33,7 +35,6 @@ float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust
|
|||
// MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees
|
||||
const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians
|
||||
// NOTE: the entity bounding cube is larger than the smallest possible containing octree element by sqrt(3)
|
||||
const float SQRT_THREE = 1.73205080f;
|
||||
const float MIN_ENTITY_ANGULAR_DIAMETER = MIN_ELEMENT_ANGULAR_DIAMETER * SQRT_THREE;
|
||||
const float MIN_VISIBLE_DISTANCE = 0.0001f; // helps avoid divide-by-zero check
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ class Transform;
|
|||
class QThread;
|
||||
class ViewFrustum;
|
||||
class PickRay;
|
||||
class ConicalViewFrustum;
|
||||
using ConicalViewFrustums = std::vector<ConicalViewFrustum>;
|
||||
|
||||
/// Interface provided by Application to other objects that need access to the current view state details
|
||||
class AbstractViewStateInterface {
|
||||
|
@ -31,9 +33,7 @@ public:
|
|||
/// copies the current view frustum for rendering the view state
|
||||
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const = 0;
|
||||
|
||||
virtual void copyViewFrustum(ViewFrustum& viewOut) const = 0;
|
||||
virtual void copySecondaryViewFrustum(ViewFrustum& viewOut) const = 0;
|
||||
virtual bool hasSecondaryViewFrustum() const = 0;
|
||||
virtual const ConicalViewFrustums& getConicalViews() const = 0;
|
||||
|
||||
virtual QThread* getMainThread() = 0;
|
||||
|
||||
|
|
|
@ -16,11 +16,21 @@
|
|||
<@include ForwardGlobalLight.slh@>
|
||||
<$declareEvalSkyboxGlobalColor()$>
|
||||
|
||||
|
||||
// the interpolated normal
|
||||
in vec3 _normalWS;
|
||||
in vec3 _normalMS;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _positionMS;
|
||||
in vec4 _positionES;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
|
|
@ -18,9 +18,18 @@
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normalWS;
|
||||
in vec3 _normalMS;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _positionMS;
|
||||
in vec4 _positionES;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
|
|
@ -16,7 +16,17 @@
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normalWS;
|
||||
in vec3 _normalMS;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _positionMS;
|
||||
in vec4 _positionES;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
|
|
|
@ -19,9 +19,19 @@
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normalWS;
|
||||
in vec3 _normalMS;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _positionMS;
|
||||
in vec4 _positionES;
|
||||
in vec4 _positionWS;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
#line 1001
|
||||
|
|
|
@ -16,7 +16,17 @@
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normalWS;
|
||||
in vec3 _normalMS;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _positionMS;
|
||||
in vec4 _positionES;
|
||||
|
||||
// For retro-compatibility
|
||||
#define _normal _normalWS
|
||||
#define _modelNormal _normalMS
|
||||
#define _position _positionMS
|
||||
#define _eyePosition _positionES
|
||||
|
||||
//PROCEDURAL_COMMON_BLOCK
|
||||
|
||||
|
|
|
@ -225,6 +225,12 @@ int unpackOrientationQuatFromSixBytes(const unsigned char* buffer, glm::quat& qu
|
|||
return 6;
|
||||
}
|
||||
|
||||
bool closeEnough(float a, float b, float relativeError) {
|
||||
assert(relativeError >= 0.0f);
|
||||
// NOTE: we add EPSILON to the denominator so we can avoid checking for division by zero.
|
||||
// This method works fine when: fabsf(a + b) >> EPSILON
|
||||
return fabsf(a - b) / (0.5f * fabsf(a + b) + EPSILON) < relativeError;
|
||||
}
|
||||
|
||||
// Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's
|
||||
// http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde,
|
||||
|
|
|
@ -137,6 +137,8 @@ int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, flo
|
|||
int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix);
|
||||
int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix);
|
||||
|
||||
bool closeEnough(float a, float b, float relativeError);
|
||||
|
||||
/// \return vec3 with euler angles in radians
|
||||
glm::vec3 safeEulerAngles(const glm::quat& q);
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ const int BYTES_PER_KILOBYTE = 1000;
|
|||
const int BYTES_PER_KILOBIT = BYTES_PER_KILOBYTE / BITS_IN_BYTE;
|
||||
const int KILO_PER_MEGA = 1000;
|
||||
|
||||
const float SQRT_THREE = 1.73205080f;
|
||||
|
||||
#define KB_TO_BYTES_SHIFT 10
|
||||
#define MB_TO_BYTES_SHIFT 20
|
||||
#define GB_TO_BYTES_SHIFT 30
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <queue>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "shared/ConicalViewFrustum.h"
|
||||
|
||||
/* PrioritySortUtil is a helper for sorting 3D things relative to a ViewFrustum. To use:
|
||||
|
||||
|
@ -84,12 +84,12 @@ namespace PrioritySortUtil {
|
|||
class PriorityQueue {
|
||||
public:
|
||||
PriorityQueue() = delete;
|
||||
PriorityQueue(const ViewFrustums& views) : _views(views) { }
|
||||
PriorityQueue(const ViewFrustums& views, float angularWeight, float centerWeight, float ageWeight)
|
||||
PriorityQueue(const ConicalViewFrustums& views) : _views(views) { }
|
||||
PriorityQueue(const ConicalViewFrustums& views, float angularWeight, float centerWeight, float ageWeight)
|
||||
: _views(views), _angularWeight(angularWeight), _centerWeight(centerWeight), _ageWeight(ageWeight)
|
||||
{ }
|
||||
|
||||
void setViews(const ViewFrustums& views) { _views = views; }
|
||||
void setViews(const ConicalViewFrustums& views) { _views = views; }
|
||||
|
||||
void setWeights(float angularWeight, float centerWeight, float ageWeight) {
|
||||
_angularWeight = angularWeight;
|
||||
|
@ -118,7 +118,7 @@ namespace PrioritySortUtil {
|
|||
return priority;
|
||||
}
|
||||
|
||||
float computePriority(const ViewFrustum& view, const T& thing) const {
|
||||
float computePriority(const ConicalViewFrustum& view, const T& thing) const {
|
||||
// priority = weighted linear combination of multiple values:
|
||||
// (a) angular size
|
||||
// (b) proximity to center of view
|
||||
|
@ -143,8 +143,8 @@ namespace PrioritySortUtil {
|
|||
+ _ageWeight * cosineAngleFactor * age;
|
||||
|
||||
// decrement priority of things outside keyhole
|
||||
if (distance - radius > view.getCenterRadius()) {
|
||||
if (!view.sphereIntersectsFrustum(position, radius)) {
|
||||
if (distance - radius > view.getRadius()) {
|
||||
if (!view.intersects(offset, distance, radius)) {
|
||||
constexpr float OUT_OF_VIEW_PENALTY = -10.0f;
|
||||
priority += OUT_OF_VIEW_PENALTY;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ namespace PrioritySortUtil {
|
|||
return priority;
|
||||
}
|
||||
|
||||
ViewFrustums _views;
|
||||
ConicalViewFrustums _views;
|
||||
std::priority_queue<T> _queue;
|
||||
float _angularWeight { DEFAULT_ANGULAR_COEF };
|
||||
float _centerWeight { DEFAULT_CENTER_COEF };
|
||||
|
|
|
@ -138,69 +138,6 @@ const char* ViewFrustum::debugPlaneName (int plane) const {
|
|||
return "Unknown";
|
||||
}
|
||||
|
||||
int ViewFrustum::fromByteArray(const QByteArray& input) {
|
||||
|
||||
// From the wire!
|
||||
glm::vec3 cameraPosition;
|
||||
glm::quat cameraOrientation;
|
||||
float cameraCenterRadius;
|
||||
float cameraFov;
|
||||
float cameraAspectRatio;
|
||||
float cameraNearClip;
|
||||
float cameraFarClip;
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(input.constData());
|
||||
const unsigned char* sourceBuffer = startPosition;
|
||||
|
||||
// camera details
|
||||
memcpy(&cameraPosition, sourceBuffer, sizeof(cameraPosition));
|
||||
sourceBuffer += sizeof(cameraPosition);
|
||||
sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, cameraOrientation);
|
||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &cameraFov);
|
||||
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, cameraAspectRatio);
|
||||
sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, cameraNearClip);
|
||||
sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, cameraFarClip);
|
||||
memcpy(&cameraCenterRadius, sourceBuffer, sizeof(cameraCenterRadius));
|
||||
sourceBuffer += sizeof(cameraCenterRadius);
|
||||
|
||||
setPosition(cameraPosition);
|
||||
setOrientation(cameraOrientation);
|
||||
setCenterRadius(cameraCenterRadius);
|
||||
|
||||
// Also make sure it's got the correct lens details from the camera
|
||||
if (0.0f != cameraAspectRatio &&
|
||||
0.0f != cameraNearClip &&
|
||||
0.0f != cameraFarClip &&
|
||||
cameraNearClip != cameraFarClip) {
|
||||
|
||||
setProjection(cameraFov, cameraAspectRatio, cameraNearClip, cameraFarClip);
|
||||
calculate();
|
||||
}
|
||||
|
||||
return sourceBuffer - startPosition;
|
||||
}
|
||||
|
||||
|
||||
QByteArray ViewFrustum::toByteArray() {
|
||||
static const int LARGE_ENOUGH = 1024;
|
||||
QByteArray viewFrustumDataByteArray(LARGE_ENOUGH, 0);
|
||||
unsigned char* destinationBuffer = reinterpret_cast<unsigned char*>(viewFrustumDataByteArray.data());
|
||||
unsigned char* startPosition = destinationBuffer;
|
||||
|
||||
// camera details
|
||||
memcpy(destinationBuffer, &_position, sizeof(_position));
|
||||
destinationBuffer += sizeof(_position);
|
||||
destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _orientation);
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _fieldOfView);
|
||||
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _aspectRatio);
|
||||
destinationBuffer += packClipValueToTwoByte(destinationBuffer, _nearClip);
|
||||
destinationBuffer += packClipValueToTwoByte(destinationBuffer, _farClip);
|
||||
memcpy(destinationBuffer, &_centerSphereRadius, sizeof(_centerSphereRadius));
|
||||
destinationBuffer += sizeof(_centerSphereRadius);
|
||||
|
||||
return viewFrustumDataByteArray.left(destinationBuffer - startPosition);
|
||||
}
|
||||
|
||||
ViewFrustum::intersection ViewFrustum::calculateCubeFrustumIntersection(const AACube& cube) const {
|
||||
// only check against frustum
|
||||
ViewFrustum::intersection result = INSIDE;
|
||||
|
@ -338,13 +275,6 @@ bool ViewFrustum::boxIntersectsKeyhole(const AABox& box) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool closeEnough(float a, float b, float relativeError) {
|
||||
assert(relativeError >= 0.0f);
|
||||
// NOTE: we add EPSILON to the denominator so we can avoid checking for division by zero.
|
||||
// This method works fine when: fabsf(a + b) >> EPSILON
|
||||
return fabsf(a - b) / (0.5f * fabsf(a + b) + EPSILON) < relativeError;
|
||||
}
|
||||
|
||||
// TODO: the slop and relative error should be passed in by argument rather than hard-coded.
|
||||
bool ViewFrustum::isVerySimilar(const ViewFrustum& other) const {
|
||||
const float MIN_POSITION_SLOP_SQUARED = 25.0f; // 5 meters squared
|
||||
|
|
|
@ -147,9 +147,6 @@ public:
|
|||
|
||||
void invalidate(); // causes all reasonable intersection tests to fail
|
||||
|
||||
QByteArray toByteArray();
|
||||
int fromByteArray(const QByteArray& input);
|
||||
|
||||
private:
|
||||
glm::mat4 _view;
|
||||
glm::mat4 _projection;
|
||||
|
|
146
libraries/shared/src/shared/ConicalViewFrustum.cpp
Normal file
146
libraries/shared/src/shared/ConicalViewFrustum.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// ConicalViewFrustum.cpp
|
||||
// libraries/shared/src/shared
|
||||
//
|
||||
// Created by Clement Brisset 4/26/18
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ConicalViewFrustum.h"
|
||||
|
||||
|
||||
#include "../NumericalConstants.h"
|
||||
#include "../ViewFrustum.h"
|
||||
|
||||
void ConicalViewFrustum::set(const ViewFrustum& viewFrustum) {
|
||||
// The ConicalViewFrustum has two parts: a central sphere (same as ViewFrustum) and a circular cone that bounds the frustum part.
|
||||
// Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum.
|
||||
_position = viewFrustum.getPosition();
|
||||
_radius = viewFrustum.getCenterRadius();
|
||||
_farClip = viewFrustum.getFarClip();
|
||||
|
||||
auto topLeft = viewFrustum.getNearTopLeft() - _position;
|
||||
auto topRight = viewFrustum.getNearTopRight() - _position;
|
||||
auto bottomLeft = viewFrustum.getNearBottomLeft() - _position;
|
||||
auto bottomRight = viewFrustum.getNearBottomRight() - _position;
|
||||
auto centerAxis = 0.25f * (topLeft + topRight + bottomLeft + bottomRight); // Take the average
|
||||
|
||||
_direction = glm::normalize(centerAxis);
|
||||
_angle = std::max(std::max(angleBetween(_direction, topLeft),
|
||||
angleBetween(_direction, topRight)),
|
||||
std::max(angleBetween(_direction, bottomLeft),
|
||||
angleBetween(_direction, bottomRight)));
|
||||
}
|
||||
|
||||
void ConicalViewFrustum::calculate() {
|
||||
// Pre-compute cos and sin for faster checks
|
||||
_cosAngle = cosf(_angle);
|
||||
_sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle);
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::isVerySimilar(const ConicalViewFrustum& other) const {
|
||||
const float MIN_POSITION_SLOP_SQUARED = 25.0f; // 5 meters squared
|
||||
const float MIN_ANGLE_BETWEEN = 0.174533f; // radian angle between 2 vectors 10 degrees apart
|
||||
const float MIN_RELATIVE_ERROR = 0.01f; // 1%
|
||||
|
||||
return glm::distance2(_position, other._position) < MIN_POSITION_SLOP_SQUARED &&
|
||||
angleBetween(_direction, other._direction) < MIN_ANGLE_BETWEEN &&
|
||||
closeEnough(_angle, other._angle, MIN_RELATIVE_ERROR) &&
|
||||
closeEnough(_farClip, other._farClip, MIN_RELATIVE_ERROR) &&
|
||||
closeEnough(_radius, other._radius, MIN_RELATIVE_ERROR);
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::intersects(const AACube& cube) const {
|
||||
auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere
|
||||
auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position);
|
||||
|
||||
return intersects(position, distance, radius);
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::intersects(const AABox& box) const {
|
||||
auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere
|
||||
auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position);
|
||||
|
||||
return intersects(position, distance, radius);
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::getAngularSize(const AACube& cube) const {
|
||||
auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere
|
||||
auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position);
|
||||
|
||||
return getAngularSize(distance, radius);
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::getAngularSize(const AABox& box) const {
|
||||
auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere
|
||||
auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||
float distance = glm::length(position);
|
||||
|
||||
return getAngularSize(distance, radius);
|
||||
}
|
||||
|
||||
|
||||
bool ConicalViewFrustum::intersects(const glm::vec3& relativePosition, float distance, float radius) const {
|
||||
if (distance < _radius + radius) {
|
||||
// Inside keyhole radius
|
||||
return true;
|
||||
}
|
||||
if (distance > _farClip + radius) {
|
||||
// Past far clip
|
||||
return false;
|
||||
}
|
||||
|
||||
// We check the angle between the center of the cube and the _direction of the view.
|
||||
// If it is less than the sum of the half-angle from center of cone to outer edge plus
|
||||
// the half apparent angle of the bounding sphere then it is in view.
|
||||
//
|
||||
// The math here is left as an exercise for the reader with the following hints:
|
||||
// (1) We actually check the dot product of the cube's local position rather than the angle and
|
||||
// (2) we take advantage of this trig identity: cos(A+B) = cos(A)*cos(B) - sin(A)*sin(B)
|
||||
return glm::dot(relativePosition, _direction) >
|
||||
sqrtf(distance * distance - radius * radius) * _cosAngle - radius * _sinAngle;
|
||||
}
|
||||
|
||||
bool ConicalViewFrustum::getAngularSize(float distance, float radius) const {
|
||||
const float AVOID_DIVIDE_BY_ZERO = 0.001f;
|
||||
float angularSize = radius / (distance + AVOID_DIVIDE_BY_ZERO);
|
||||
return angularSize;
|
||||
}
|
||||
|
||||
int ConicalViewFrustum::serialize(unsigned char* destinationBuffer) const {
|
||||
const unsigned char* startPosition = destinationBuffer;
|
||||
|
||||
memcpy(destinationBuffer, &_position, sizeof(_position));
|
||||
destinationBuffer += sizeof(_position);
|
||||
memcpy(destinationBuffer, &_direction, sizeof(_direction));
|
||||
destinationBuffer += sizeof(_direction);
|
||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _angle);
|
||||
destinationBuffer += packClipValueToTwoByte(destinationBuffer, _farClip);
|
||||
memcpy(destinationBuffer, &_radius, sizeof(_radius));
|
||||
destinationBuffer += sizeof(_radius);
|
||||
|
||||
return destinationBuffer - startPosition;
|
||||
}
|
||||
|
||||
int ConicalViewFrustum::deserialize(const unsigned char* sourceBuffer) {
|
||||
const unsigned char* startPosition = sourceBuffer;
|
||||
|
||||
memcpy(&_position, sourceBuffer, sizeof(_position));
|
||||
sourceBuffer += sizeof(_position);
|
||||
memcpy(&_direction, sourceBuffer, sizeof(_direction));
|
||||
sourceBuffer += sizeof(_direction);
|
||||
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &_angle);
|
||||
sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer, _farClip);
|
||||
memcpy(&_radius, sourceBuffer, sizeof(_radius));
|
||||
sourceBuffer += sizeof(_radius);
|
||||
|
||||
calculate();
|
||||
|
||||
return sourceBuffer - startPosition;
|
||||
}
|
70
libraries/shared/src/shared/ConicalViewFrustum.h
Normal file
70
libraries/shared/src/shared/ConicalViewFrustum.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// ConicalViewFrustum.h
|
||||
// libraries/shared/src/shared
|
||||
//
|
||||
// Created by Clement Brisset 4/26/18
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ConicalViewFrustum_h
|
||||
#define hifi_ConicalViewFrustum_h
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class AACube;
|
||||
class AABox;
|
||||
class ViewFrustum;
|
||||
using ViewFrustums = std::vector<ViewFrustum>;
|
||||
|
||||
const float SQRT_TWO_OVER_TWO = 0.7071067811865f;
|
||||
const float DEFAULT_VIEW_ANGLE = 1.0f;
|
||||
const float DEFAULT_VIEW_RADIUS = 10.0f;
|
||||
const float DEFAULT_VIEW_FAR_CLIP = 100.0f;
|
||||
|
||||
// ConicalViewFrustum is an approximation of a ViewFrustum for fast calculation of sort priority.
|
||||
class ConicalViewFrustum {
|
||||
public:
|
||||
ConicalViewFrustum() = default;
|
||||
ConicalViewFrustum(const ViewFrustum& viewFrustum) { set(viewFrustum); }
|
||||
|
||||
void set(const ViewFrustum& viewFrustum);
|
||||
void calculate();
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
const glm::vec3& getDirection() const { return _direction; }
|
||||
float getAngle() const { return _angle; }
|
||||
float getRadius() const { return _radius; }
|
||||
float getFarClip() const { return _farClip; }
|
||||
|
||||
bool isVerySimilar(const ConicalViewFrustum& other) const;
|
||||
|
||||
bool intersects(const AACube& cube) const;
|
||||
bool intersects(const AABox& box) const;
|
||||
bool getAngularSize(const AACube& cube) const;
|
||||
bool getAngularSize(const AABox& box) const;
|
||||
|
||||
bool intersects(const glm::vec3& relativePosition, float distance, float radius) const;
|
||||
bool getAngularSize(float distance, float radius) const;
|
||||
|
||||
int serialize(unsigned char* destinationBuffer) const;
|
||||
int deserialize(const unsigned char* sourceBuffer);
|
||||
|
||||
private:
|
||||
glm::vec3 _position { 0.0f, 0.0f, 0.0f };
|
||||
glm::vec3 _direction { 0.0f, 0.0f, 1.0f };
|
||||
float _angle { DEFAULT_VIEW_ANGLE };
|
||||
float _radius { DEFAULT_VIEW_RADIUS };
|
||||
float _farClip { DEFAULT_VIEW_FAR_CLIP };
|
||||
|
||||
float _sinAngle { SQRT_TWO_OVER_TWO };
|
||||
float _cosAngle { SQRT_TWO_OVER_TWO };
|
||||
};
|
||||
using ConicalViewFrustums = std::vector<ConicalViewFrustum>;
|
||||
|
||||
|
||||
#endif /* hifi_ConicalViewFrustum_h */
|
355
server-console/package-lock.json
generated
355
server-console/package-lock.json
generated
|
@ -20,7 +20,6 @@
|
|||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"co": "4.6.0",
|
||||
"fast-deep-equal": "1.0.0",
|
||||
|
@ -41,11 +40,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
|
||||
"integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||
},
|
||||
"array-find-index": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz",
|
||||
|
@ -118,16 +112,10 @@
|
|||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
|
||||
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
|
||||
},
|
||||
"async": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"author-regex": {
|
||||
"version": "1.0.0",
|
||||
|
@ -136,17 +124,14 @@
|
|||
"dev": true
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
|
||||
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8="
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.3.2.tgz",
|
||||
"integrity": "sha1-054L7kEs7Q6O2Uoj4xTzE6lbn9E=",
|
||||
"requires": {
|
||||
"lru-cache": "4.0.1"
|
||||
}
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
|
||||
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.2.0",
|
||||
|
@ -204,11 +189,11 @@
|
|||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
},
|
||||
"buffers": {
|
||||
|
@ -239,9 +224,9 @@
|
|||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
|
||||
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"chainsaw": {
|
||||
"version": "0.1.0",
|
||||
|
@ -252,18 +237,6 @@
|
|||
"traverse": "0.3.9"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "2.2.1",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"has-ansi": "2.0.0",
|
||||
"strip-ansi": "3.0.1",
|
||||
"supports-color": "2.0.0"
|
||||
}
|
||||
},
|
||||
"cheerio": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz",
|
||||
|
@ -295,8 +268,7 @@
|
|||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.0.0",
|
||||
|
@ -318,6 +290,7 @@
|
|||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
|
||||
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-readlink": "1.0.1"
|
||||
}
|
||||
|
@ -373,11 +346,21 @@
|
|||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cryptiles": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
|
||||
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
|
||||
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
|
||||
"requires": {
|
||||
"boom": "2.10.1"
|
||||
"boom": "5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
|
||||
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
|
||||
"requires": {
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
|
@ -728,7 +711,7 @@
|
|||
"minimist": "1.2.0",
|
||||
"pretty-bytes": "1.0.4",
|
||||
"progress-stream": "1.2.0",
|
||||
"request": "2.71.0",
|
||||
"request": "2.85.0",
|
||||
"single-line-log": "1.1.2",
|
||||
"throttleit": "0.0.2"
|
||||
},
|
||||
|
@ -828,11 +811,6 @@
|
|||
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
|
||||
|
@ -875,14 +853,12 @@
|
|||
"fast-deep-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
|
||||
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
|
||||
"dev": true
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
|
||||
},
|
||||
"fd-slicer": {
|
||||
"version": "1.0.1",
|
||||
|
@ -976,13 +952,23 @@
|
|||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "1.0.0-rc4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz",
|
||||
"integrity": "sha1-BaxrwiIntD5EYfSIFhVUaZ1Pi14=",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
|
||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
||||
"requires": {
|
||||
"async": "1.5.2",
|
||||
"combined-stream": "1.0.5",
|
||||
"mime-types": "2.1.10"
|
||||
"asynckit": "0.4.0",
|
||||
"combined-stream": "1.0.6",
|
||||
"mime-types": "2.1.18"
|
||||
},
|
||||
"dependencies": {
|
||||
"combined-stream": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
|
||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
||||
"requires": {
|
||||
"delayed-stream": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
|
@ -1058,19 +1044,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"generate-function": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
|
||||
"integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ="
|
||||
},
|
||||
"generate-object-property": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
|
||||
"integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
|
||||
"requires": {
|
||||
"is-property": "1.0.2"
|
||||
}
|
||||
},
|
||||
"get-package-info": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-package-info/-/get-package-info-1.0.0.tgz",
|
||||
|
@ -1212,7 +1185,8 @@
|
|||
"graceful-readlink": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
|
||||
"dev": true
|
||||
},
|
||||
"growly": {
|
||||
"version": "1.3.0",
|
||||
|
@ -1222,43 +1196,32 @@
|
|||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
|
||||
"integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
|
||||
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
||||
"requires": {
|
||||
"chalk": "1.1.3",
|
||||
"commander": "2.9.0",
|
||||
"is-my-json-valid": "2.13.1",
|
||||
"pinkie-promise": "2.0.1"
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"requires": {
|
||||
"ansi-regex": "2.0.0"
|
||||
"ajv": "5.5.2",
|
||||
"har-schema": "2.0.0"
|
||||
}
|
||||
},
|
||||
"hawk": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
|
||||
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
|
||||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
"hoek": "2.16.3",
|
||||
"sntp": "1.0.9"
|
||||
"boom": "4.3.1",
|
||||
"cryptiles": "3.1.2",
|
||||
"hoek": "4.2.1",
|
||||
"sntp": "2.1.0"
|
||||
}
|
||||
},
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
|
||||
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
|
||||
},
|
||||
"home-path": {
|
||||
"version": "1.0.5",
|
||||
|
@ -1301,13 +1264,20 @@
|
|||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
|
||||
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "0.2.0",
|
||||
"assert-plus": "1.0.0",
|
||||
"jsprim": "1.2.2",
|
||||
"sshpk": "1.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"indent-string": {
|
||||
|
@ -1388,28 +1358,12 @@
|
|||
"number-is-nan": "1.0.0"
|
||||
}
|
||||
},
|
||||
"is-my-json-valid": {
|
||||
"version": "2.13.1",
|
||||
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz",
|
||||
"integrity": "sha1-1Vd4qC/rawlj/0vhEdXRaE6JBwc=",
|
||||
"requires": {
|
||||
"generate-function": "2.0.0",
|
||||
"generate-object-property": "1.2.0",
|
||||
"jsonpointer": "2.0.0",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"is-promise": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz",
|
||||
"integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=",
|
||||
"dev": true
|
||||
},
|
||||
"is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
|
@ -1465,8 +1419,7 @@
|
|||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
|
||||
"dev": true
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
|
@ -1478,11 +1431,6 @@
|
|||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz",
|
||||
"integrity": "sha1-4lK5mmr5AdPsQfMyWJyQUJp7xgU="
|
||||
},
|
||||
"jsonpointer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz",
|
||||
"integrity": "sha1-OvHdIP6FRjkQ1GmjheMwF9KgMNk="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
|
||||
|
@ -1569,15 +1517,6 @@
|
|||
"signal-exit": "2.1.2"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz",
|
||||
"integrity": "sha1-E0OVXtry432bnn7nJB4nxLn7cr4=",
|
||||
"requires": {
|
||||
"pseudomap": "1.0.2",
|
||||
"yallist": "2.0.0"
|
||||
}
|
||||
},
|
||||
"map-obj": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
|
||||
|
@ -1603,16 +1542,16 @@
|
|||
}
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.22.0.tgz",
|
||||
"integrity": "sha1-qyOmNy3J2G09yRIb0OvTgQWhkEo="
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
|
||||
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
|
||||
"integrity": "sha1-uTx8tDYuFtQQcqflRTj7TUMHCDc=",
|
||||
"version": "2.1.18",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
|
||||
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
|
||||
"requires": {
|
||||
"mime-db": "1.22.0"
|
||||
"mime-db": "1.33.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
|
@ -1891,11 +1830,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node-uuid": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz",
|
||||
"integrity": "sha1-baWhdmjEs91ZYjvaEc9/pMH2Cm8="
|
||||
},
|
||||
"nodeify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz",
|
||||
|
@ -1945,7 +1879,7 @@
|
|||
"minimist": "1.2.0",
|
||||
"pretty-bytes": "1.0.4",
|
||||
"progress-stream": "1.2.0",
|
||||
"request": "2.71.0",
|
||||
"request": "2.85.0",
|
||||
"single-line-log": "1.1.2",
|
||||
"throttleit": "0.0.2"
|
||||
},
|
||||
|
@ -1973,9 +1907,9 @@
|
|||
"integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es="
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz",
|
||||
"integrity": "sha1-GCQ5vbkTeL90YOdcZOpD5kSN7wY="
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.0.1",
|
||||
|
@ -2099,8 +2033,7 @@
|
|||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
|
@ -2111,12 +2044,14 @@
|
|||
"pinkie": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
|
||||
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
|
||||
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
|
||||
"dev": true
|
||||
},
|
||||
"pinkie-promise": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
|
||||
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pinkie": "2.0.4"
|
||||
}
|
||||
|
@ -2166,11 +2101,6 @@
|
|||
"is-promise": "1.0.1"
|
||||
}
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||
},
|
||||
"pump": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.1.tgz",
|
||||
|
@ -2183,8 +2113,7 @@
|
|||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
|
@ -2193,9 +2122,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.1.0.tgz",
|
||||
"integrity": "sha1-7B0WJrJCeNmfD99FSeUk4k7O6yY="
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.1.6",
|
||||
|
@ -2252,31 +2181,39 @@
|
|||
}
|
||||
},
|
||||
"request": {
|
||||
"version": "2.71.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.71.0.tgz",
|
||||
"integrity": "sha1-bxRkPJxaZ8ruapXPjvBHfVYDvZE=",
|
||||
"version": "2.85.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
|
||||
"integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==",
|
||||
"requires": {
|
||||
"aws-sign2": "0.6.0",
|
||||
"aws4": "1.3.2",
|
||||
"bl": "1.1.2",
|
||||
"caseless": "0.11.0",
|
||||
"aws-sign2": "0.7.0",
|
||||
"aws4": "1.7.0",
|
||||
"caseless": "0.12.0",
|
||||
"combined-stream": "1.0.5",
|
||||
"extend": "3.0.0",
|
||||
"extend": "3.0.1",
|
||||
"forever-agent": "0.6.1",
|
||||
"form-data": "1.0.0-rc4",
|
||||
"har-validator": "2.0.6",
|
||||
"hawk": "3.1.3",
|
||||
"http-signature": "1.1.1",
|
||||
"form-data": "2.3.2",
|
||||
"har-validator": "5.0.3",
|
||||
"hawk": "6.0.2",
|
||||
"http-signature": "1.2.0",
|
||||
"is-typedarray": "1.0.0",
|
||||
"isstream": "0.1.2",
|
||||
"json-stringify-safe": "5.0.1",
|
||||
"mime-types": "2.1.10",
|
||||
"node-uuid": "1.4.7",
|
||||
"oauth-sign": "0.8.1",
|
||||
"qs": "6.1.0",
|
||||
"mime-types": "2.1.18",
|
||||
"oauth-sign": "0.8.2",
|
||||
"performance-now": "2.1.0",
|
||||
"qs": "6.5.1",
|
||||
"safe-buffer": "5.1.1",
|
||||
"stringstream": "0.0.5",
|
||||
"tough-cookie": "2.2.2",
|
||||
"tunnel-agent": "0.4.2"
|
||||
"tough-cookie": "2.3.4",
|
||||
"tunnel-agent": "0.6.0",
|
||||
"uuid": "3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"extend": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-progress": {
|
||||
|
@ -2308,8 +2245,7 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
},
|
||||
"sanitize-filename": {
|
||||
"version": "1.6.1",
|
||||
|
@ -2347,11 +2283,11 @@
|
|||
}
|
||||
},
|
||||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
|
||||
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
"hoek": "4.2.1"
|
||||
}
|
||||
},
|
||||
"spdx-correct": {
|
||||
|
@ -2483,11 +2419,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||
},
|
||||
"tar-fs": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.12.0.tgz",
|
||||
|
@ -2585,9 +2516,12 @@
|
|||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz",
|
||||
"integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc="
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
|
||||
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
|
||||
"requires": {
|
||||
"punycode": "1.4.1"
|
||||
}
|
||||
},
|
||||
"traverse": {
|
||||
"version": "0.3.9",
|
||||
|
@ -2611,9 +2545,12 @@
|
|||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz",
|
||||
"integrity": "sha1-EQTj82rIcSXChycAZ9WC0YEzv+4="
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.3",
|
||||
|
@ -2644,6 +2581,11 @@
|
|||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
|
||||
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
|
||||
|
@ -2710,11 +2652,6 @@
|
|||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
|
||||
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz",
|
||||
"integrity": "sha1-MGxUODXwnuGkyyO3vOmrNByRzdQ="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"fs-extra": "^1.0.0",
|
||||
"node-notifier": "^5.2.1",
|
||||
"os-homedir": "^1.0.1",
|
||||
"request": "^2.67.0",
|
||||
"request": "^2.85.0",
|
||||
"request-progress": "1.0.2",
|
||||
"tar-fs": "^1.12.0",
|
||||
"yargs": "^3.30.0"
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <shared/ConicalViewFrustum.h>
|
||||
#include <shared/RateCounter.h>
|
||||
#include <shared/NetworkUtils.h>
|
||||
#include <shared/FileLogger.h>
|
||||
|
@ -441,14 +442,8 @@ protected:
|
|||
viewOut = _viewFrustum;
|
||||
}
|
||||
|
||||
void copyViewFrustum(ViewFrustum& viewOut) const override {
|
||||
viewOut = _viewFrustum;
|
||||
}
|
||||
|
||||
void copySecondaryViewFrustum(ViewFrustum& viewOut) const override {}
|
||||
|
||||
bool hasSecondaryViewFrustum() const override {
|
||||
return false;
|
||||
const ConicalViewFrustums& getConicalViews() const override {
|
||||
return _view;
|
||||
}
|
||||
|
||||
QThread* getMainThread() override {
|
||||
|
@ -1126,6 +1121,7 @@ private:
|
|||
graphics::LightPointer _globalLight { std::make_shared<graphics::Light>() };
|
||||
bool _ready { false };
|
||||
EntitySimulationPointer _entitySimulation;
|
||||
ConicalViewFrustums _view;
|
||||
|
||||
QStringList _commands;
|
||||
QString _commandPath;
|
||||
|
|
Loading…
Reference in a new issue