Move all wire frustums to conical frustums

This commit is contained in:
Clement 2018-05-01 15:57:26 -07:00
parent 3283c5eaec
commit 27c471ee97
24 changed files with 181 additions and 257 deletions

View file

@ -614,13 +614,19 @@ void Agent::sendAvatarViewFrustum() {
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::AvatarQuery, 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 });

View file

@ -128,15 +128,16 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self,
void AvatarMixerClientData::readViewFrustumPacket(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);
});
}

View file

@ -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";
@ -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 };

View file

@ -107,16 +107,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
DiffTraversal::View newView;
ConicalViewFrustum 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);

View file

@ -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>();

View file

@ -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()));
}

View file

@ -5230,10 +5230,10 @@ void Application::updateSecondaryCameraViewFrustum() {
assert(camera);
if (!camera->isEnabled()) {
_hasSecondaryViewFrustum = false;
return;
}
ViewFrustum secondaryViewFrustum;
if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId);
@ -5258,36 +5258,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;
@ -5644,6 +5645,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,18 +5663,29 @@ void Application::update(float deltaTime) {
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;
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
queryOctree(NodeType::EntityServer, PacketType::EntityQuery);
}
sendAvatarViewFrustum();
_lastQueriedViewFrustum = _viewFrustum;
_lastQueriedSecondaryViewFrustum = _secondaryViewFrustum;
_lastQueriedViews = _conicalViews;
_lastQueriedTime = now;
}
}
@ -5844,17 +5858,19 @@ void Application::update(float deltaTime) {
}
void Application::sendAvatarViewFrustum() {
uint8_t numFrustums = 1;
QByteArray viewFrustumByteArray = _viewFrustum.toByteArray();
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 = _conicalViews.size();
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
destinationBuffer += sizeof(numFrustums);
for (const auto& view : _conicalViews) {
destinationBuffer += view.serialize(destinationBuffer);
}
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery, viewFrustumByteArray.size() + sizeof(numFrustums));
avatarPacket->writePrimitive(numFrustums);
avatarPacket->write(viewFrustumByteArray);
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
}
@ -5916,16 +5932,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());
@ -6010,11 +6017,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();

View file

@ -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>
@ -175,14 +176,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; }
@ -574,11 +575,10 @@ 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;
ConicalViewFrustums _conicalViews;
ConicalViewFrustums _lastQueriedViews; // last views used to query servers
quint64 _lastQueriedTime;
OctreeQuery _octreeQuery { true }; // NodeData derived class for querying octee cells from octree servers

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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()); }

View file

@ -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,23 +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 = _conicalViews.size();
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
destinationBuffer += sizeof(numFrustums);
if (_hasMainFrustum) {
destinationBuffer += _mainViewFrustum.serialize(destinationBuffer);
}
if (_hasSecondaryFrustum) {
destinationBuffer += _secondaryViewFrustum.serialize(destinationBuffer);
for (const auto& view : _conicalViews) {
destinationBuffer += view.serialize(destinationBuffer);
}
// desired Max Octree PPS
@ -118,19 +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) {
sourceBuffer += _mainViewFrustum.deserialize(sourceBuffer);
}
if (_hasSecondaryFrustum) {
sourceBuffer += _secondaryViewFrustum.deserialize(sourceBuffer);
_conicalViews.clear();
for (int i = 0; i < numFrustums; ++i) {
ConicalViewFrustum view;
sourceBuffer += view.deserialize(sourceBuffer);
_conicalViews.push_back(view);
}
// desired Max Octree PPS

View file

@ -33,13 +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; }
bool hasSecondaryViewFrustum() const { return _hasSecondaryFrustum; }
void setSecondaryViewFrustum(const ViewFrustum& viewFrustum) { _hasSecondaryFrustum = true; _secondaryViewFrustum = viewFrustum; }
void clearSecondaryViewFrustum() { _hasSecondaryFrustum = false; }
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; }
@ -64,10 +60,7 @@ public slots:
void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; }
protected:
bool _hasMainFrustum { false };
ConicalViewFrustum _mainViewFrustum;
bool _hasSecondaryFrustum { false };
ConicalViewFrustum _secondaryViewFrustum;
ConicalViewFrustums _conicalViews;
// octree server sending items
int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS;

View file

@ -139,23 +139,13 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, unsigned int by
}
}
void OctreeQueryNode::copyCurrentMainViewFrustum(ConicalViewFrustum& viewOut) const {
QMutexLocker viewLocker(&_viewMutex);
viewOut = _currentMainViewFrustum;
}
void OctreeQueryNode::copyCurrentSecondaryViewFrustum(ConicalViewFrustum& 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;
}
}

View file

@ -49,8 +49,7 @@ public:
OctreeElementExtraEncodeData extraEncodeData;
void copyCurrentMainViewFrustum(ConicalViewFrustum& viewOut) const;
void copyCurrentSecondaryViewFrustum(ConicalViewFrustum& 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 };
ConicalViewFrustum _currentMainViewFrustum;
ConicalViewFrustum _currentSecondaryViewFrustum;
ConicalViewFrustums _currentConicalViews;
bool _viewFrustumChanging { false };
bool _viewFrustumJustStoppedChanging { true };

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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 };

View file

@ -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;

View file

@ -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;

View file

@ -11,6 +11,8 @@
#include "ConicalViewFrustum.h"
#include "../NumericalConstants.h"
#include "../ViewFrustum.h"
void ConicalViewFrustum::set(const ViewFrustum& viewFrustum) {
@ -45,13 +47,46 @@ bool ConicalViewFrustum::isVerySimilar(const ConicalViewFrustum& other) const {
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);
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 glm::vec3& position, float distance, float radius) const {
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;
@ -68,7 +103,7 @@ bool ConicalViewFrustum::intersects(const glm::vec3& position, float distance, f
// 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(position, _direction) >
return glm::dot(relativePosition, _direction) >
sqrtf(distance * distance - radius * radius) * _cosAngle - radius * _sinAngle;
}

View file

@ -17,6 +17,7 @@
#include <glm/glm.hpp>
class AACube;
class AABox;
class ViewFrustum;
using ViewFrustums = std::vector<ViewFrustum>;
@ -42,7 +43,12 @@ public:
bool isVerySimilar(const ConicalViewFrustum& other) const;
bool intersects(const glm::vec3& position, float distance, float radius) 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;

View file

@ -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,9 @@ 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 {
assert(false);
return ConicalViewFrustums();
}
QThread* getMainThread() override {