From 27c471ee9774f2fd98c0584402ad7a7242c5ad18 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 1 May 2018 15:57:26 -0700 Subject: [PATCH] Move all wire frustums to conical frustums --- assignment-client/src/Agent.cpp | 14 +++- .../src/avatars/AvatarMixerClientData.cpp | 15 ++-- .../src/avatars/AvatarMixerClientData.h | 6 +- .../src/entities/EntityTreeSendThread.cpp | 11 +-- .../src/octree/OctreeHeadlessViewer.cpp | 5 +- .../src/octree/OctreeSendThread.cpp | 2 +- interface/src/Application.cpp | 80 ++++++++++--------- interface/src/Application.h | 14 ++-- interface/src/avatar/AvatarManager.cpp | 13 +-- .../src/EntityTreeRenderer.cpp | 19 +---- .../src/EntityTreeRenderer.h | 3 +- libraries/octree/src/OctreeQuery.cpp | 46 ++++------- libraries/octree/src/OctreeQuery.h | 15 +--- libraries/octree/src/OctreeQueryNode.cpp | 29 +++---- libraries/octree/src/OctreeQueryNode.h | 6 +- libraries/octree/src/OctreeUtils.h | 3 +- .../src/AbstractViewStateInterface.h | 6 +- libraries/shared/src/NumericalConstants.h | 2 + libraries/shared/src/PrioritySortUtil.h | 16 ++-- libraries/shared/src/ViewFrustum.cpp | 63 --------------- libraries/shared/src/ViewFrustum.h | 3 - .../shared/src/shared/ConicalViewFrustum.cpp | 47 +++++++++-- .../shared/src/shared/ConicalViewFrustum.h | 8 +- tests/render-perf/src/main.cpp | 12 +-- 24 files changed, 181 insertions(+), 257 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0183248648..da811b8af5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -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(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()->broadcastToNodes(std::move(avatarPacket), { NodeType::AvatarMixer }); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index a8e5a7c541..aa93fc9e08 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -128,15 +128,16 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self, void AvatarMixerClientData::readViewFrustumPacket(QByteArray message) { _currentViewFrustums.clear(); + + auto sourceBuffer = reinterpret_cast(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); }); } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index f17404b79f..f3b2b587ee 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include 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 _radiusIgnoredOthers; - ViewFrustums _currentViewFrustums; + ConicalViewFrustums _currentViewFrustums; int _recentOtherAvatarsInView { 0 }; int _recentOtherAvatarsOutOfView { 0 }; diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 1851714f0d..f008ef9925 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -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); diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.cpp b/assignment-client/src/octree/OctreeHeadlessViewer.cpp index 6d91a134c2..039dbdab78 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.cpp +++ b/assignment-client/src/octree/OctreeHeadlessViewer.cpp @@ -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(); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 40c052659d..482b20272a 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -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())); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a1301ff43e..d14af685f0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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(); 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(); 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()->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(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()->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(); _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()->reset(); DependencyManager::get()->reset(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 83e719333d..6d749f9458 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -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 getEntities() const { return DependencyManager::get(); } 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 diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 087e23a933..d24618fada 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #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 sortedAvatars(views, AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 6dd13c7332..600d1c32a8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -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 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 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); } } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 9ed4f9d21d..882ec2fd5b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -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()); } diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 7aa702138f..072774f0f5 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -18,10 +18,6 @@ #include #include -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 diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index f28d4c317e..7dfc1cfaaf 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -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; diff --git a/libraries/octree/src/OctreeQueryNode.cpp b/libraries/octree/src/OctreeQueryNode.cpp index 568504a344..2d1d89a11c 100644 --- a/libraries/octree/src/OctreeQueryNode.cpp +++ b/libraries/octree/src/OctreeQueryNode.cpp @@ -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; } } diff --git a/libraries/octree/src/OctreeQueryNode.h b/libraries/octree/src/OctreeQueryNode.h index 13337c2c69..d984e048c1 100644 --- a/libraries/octree/src/OctreeQueryNode.h +++ b/libraries/octree/src/OctreeQueryNode.h @@ -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 }; diff --git a/libraries/octree/src/OctreeUtils.h b/libraries/octree/src/OctreeUtils.h index 58ab366d8d..dff56cad64 100644 --- a/libraries/octree/src/OctreeUtils.h +++ b/libraries/octree/src/OctreeUtils.h @@ -12,6 +12,8 @@ #ifndef hifi_OctreeUtils_h #define hifi_OctreeUtils_h +#include + #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 diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 9d781b7d18..b90e291da5 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -24,6 +24,8 @@ class Transform; class QThread; class ViewFrustum; class PickRay; +class ConicalViewFrustum; +using ConicalViewFrustums = std::vector; /// 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; diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index e2d2409d56..4c24a73226 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -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 diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index ba15222611..34ec074d45 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -15,7 +15,7 @@ #include #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 _queue; float _angularWeight { DEFAULT_ANGULAR_COEF }; float _centerWeight { DEFAULT_CENTER_COEF }; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index c89a9fbd60..3aa70b0897 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -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(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(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; diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 128a717df8..eada65468d 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -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; diff --git a/libraries/shared/src/shared/ConicalViewFrustum.cpp b/libraries/shared/src/shared/ConicalViewFrustum.cpp index 8538543da6..2ef096e3a8 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.cpp +++ b/libraries/shared/src/shared/ConicalViewFrustum.cpp @@ -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; } diff --git a/libraries/shared/src/shared/ConicalViewFrustum.h b/libraries/shared/src/shared/ConicalViewFrustum.h index 3cadedda9d..dc372d560e 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.h +++ b/libraries/shared/src/shared/ConicalViewFrustum.h @@ -17,6 +17,7 @@ #include class AACube; +class AABox; class ViewFrustum; using ViewFrustums = std::vector; @@ -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; diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 8c17d7c5c2..2e72d9cead 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -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 {