From e5091e7f59d6e078b9f2a2ddbd42aac7241f1d98 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 25 Feb 2019 15:44:52 -0800 Subject: [PATCH] Fixes for EntityItem contains test, add MixerAvatar class and use in sort --- .../src/avatars/AvatarMixerClientData.cpp | 4 +- .../src/avatars/AvatarMixerClientData.h | 12 +-- .../src/avatars/AvatarMixerSlave.cpp | 80 +++++++++++++------ assignment-client/src/avatars/MixerAvatar.h | 31 +++++++ libraries/entities/src/EntityItem.cpp | 2 +- 5 files changed, 94 insertions(+), 35 deletions(-) create mode 100644 assignment-client/src/avatars/MixerAvatar.h diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 9edbae12d8..9ba1ea82ca 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -135,9 +135,7 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveShared EntityTree& entityTree = *slaveSharedData.entityTree; FindPriorityZone findPriorityZone { newPosition, false } ; entityTree.recurseTreeWithOperation(&FindPriorityZone::operation, &findPriorityZone); - if (findPriorityZone.isInPriorityZone) { - // Tag avatar as hero ... - } + _avatar->setPriorityAvatar(findPriorityZone.isInPriorityZone); } return true; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 45d508088c..a11f218a7b 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -21,7 +21,7 @@ #include #include -#include +#include "MixerAvatar.h" #include #include #include @@ -46,10 +46,10 @@ public: using PerNodeTraitVersions = std::unordered_map; int parseData(ReceivedMessage& message, const SlaveSharedData& SlaveSharedData); - AvatarData& getAvatar() { return *_avatar; } - const AvatarData& getAvatar() const { return *_avatar; } - const AvatarData* getConstAvatarData() const { return _avatar.get(); } - AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; } + MixerAvatar& getAvatar() { return *_avatar; } + const MixerAvatar& getAvatar() const { return *_avatar; } + const MixerAvatar* getConstAvatarData() const { return _avatar.get(); } + MixerAvatarSharedPointer getAvatarSharedPointer() const { return _avatar; } uint16_t getLastBroadcastSequenceNumber(NLPacket::LocalID nodeID) const; void setLastBroadcastSequenceNumber(NLPacket::LocalID nodeID, uint16_t sequenceNumber) @@ -163,7 +163,7 @@ private: }; PacketQueue _packetQueue; - AvatarSharedPointer _avatar { new AvatarData() }; + MixerAvatarSharedPointer _avatar { new MixerAvatar() }; uint16_t _lastReceivedSequenceNumber { 0 }; std::unordered_map _lastBroadcastSequenceNumbers; diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 6b039e2c03..7d25268a6b 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -281,7 +281,51 @@ AABox computeBubbleBox(const AvatarData& avatar, float bubbleExpansionFactor) { return box; } +namespace { + class SortableAvatar : public PrioritySortUtil::Sortable { + public: + SortableAvatar() = delete; + SortableAvatar(const MixerAvatar* avatar, const Node* avatarNode, uint64_t lastEncodeTime) + : _avatar(avatar), _node(avatarNode), _lastEncodeTime(lastEncodeTime) { + } + glm::vec3 getPosition() const override { return _avatar->getClientGlobalPosition(); } + float getRadius() const override { + glm::vec3 nodeBoxScale = _avatar->getGlobalBoundingBox().getScale(); + return 0.5f * glm::max(nodeBoxScale.x, glm::max(nodeBoxScale.y, nodeBoxScale.z)); + } + uint64_t getTimestamp() const override { + return _lastEncodeTime; + } + const Node* getNode() const { return _node; } + const MixerAvatar* getAvatar() const { return _avatar; } + + private: + const MixerAvatar* _avatar; + const Node* _node; + uint64_t _lastEncodeTime; + }; + +} // Close anonymous namespace. + +// Specialize computePriority() for avatars: +template<> float PrioritySortUtil::PriorityQueue::computePriority(const SortableAvatar& thing) const { + static constexpr float AVATAR_HERO_BONUS { 25.0f }; // Higher than any normal priority. + + float priority = std::numeric_limits::min(); + + for (const auto& view : _views) { + priority = std::max(priority, computePriority(view, thing)); + } + + if (thing.getAvatar()->getPriorityAvatar()) { + priority += AVATAR_HERO_BONUS; + } + + return priority; +} + void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) { + const float AVATAR_HERO_FRACTION { 0.4f }; const Node* destinationNode = node.data(); auto nodeList = DependencyManager::get(); @@ -314,8 +358,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) int identityBytesSent = 0; int traitBytesSent = 0; - // max number of avatarBytes per frame - int maxAvatarBytesPerFrame = int(_maxKbpsPerNode * BYTES_PER_KILOBIT / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND); + // max number of avatarBytes per frame (13 900, typical) + const int maxAvatarBytesPerFrame = int(_maxKbpsPerNode * BYTES_PER_KILOBIT / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND); + const int maxHeroBytesPerFrame = int(maxAvatarBytesPerFrame * AVATAR_HERO_FRACTION); // 5555, typical // keep track of the number of other avatars held back in this frame int numAvatarsHeldBack = 0; @@ -339,27 +384,6 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) const float MY_AVATAR_BUBBLE_EXPANSION_FACTOR = 4.0f; // magic number determined emperically AABox nodeBox = computeBubbleBox(avatar, MY_AVATAR_BUBBLE_EXPANSION_FACTOR); - class SortableAvatar: public PrioritySortUtil::Sortable { - public: - SortableAvatar() = delete; - SortableAvatar(const AvatarData* avatar, const Node* avatarNode, uint64_t lastEncodeTime) - : _avatar(avatar), _node(avatarNode), _lastEncodeTime(lastEncodeTime) {} - glm::vec3 getPosition() const override { return _avatar->getClientGlobalPosition(); } - float getRadius() const override { - glm::vec3 nodeBoxScale = _avatar->getGlobalBoundingBox().getScale(); - return 0.5f * glm::max(nodeBoxScale.x, glm::max(nodeBoxScale.y, nodeBoxScale.z)); - } - uint64_t getTimestamp() const override { - return _lastEncodeTime; - } - const Node* getNode() const { return _node; } - - private: - const AvatarData* _avatar; - const Node* _node; - uint64_t _lastEncodeTime; - }; - // prepare to sort const auto& cameraViews = nodeData->getViewFrustums(); PrioritySortUtil::PriorityQueue sortedAvatars(cameraViews, @@ -446,7 +470,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) if (!shouldIgnore) { // sort this one for later - const AvatarData* avatarNodeData = avatarClientNodeData->getConstAvatarData(); + const MixerAvatar* avatarNodeData = avatarClientNodeData->getConstAvatarData(); auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNode->getLocalID()); sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime)); @@ -508,10 +532,16 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) } } + bool overHeroBudget = frameByteEstimate > maxHeroBytesPerFrame; + auto startAvatarDataPacking = chrono::high_resolution_clock::now(); const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - const AvatarData* otherAvatar = otherNodeData->getConstAvatarData(); + const MixerAvatar* otherAvatar = otherNodeData->getConstAvatarData(); + + if (overHeroBudget && otherAvatar->getPriorityAvatar()) { + continue; // No more heroes (this frame). + } // Typically all out-of-view avatars but such avatars' priorities will rise with time: bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD; diff --git a/assignment-client/src/avatars/MixerAvatar.h b/assignment-client/src/avatars/MixerAvatar.h new file mode 100644 index 0000000000..4781fdee1b --- /dev/null +++ b/assignment-client/src/avatars/MixerAvatar.h @@ -0,0 +1,31 @@ +// +// MixerAvatar.h +// assignment-client/src/avatars +// +// Created by Simon Walton Feb 2019. +// Copyright 2019 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 +// + +// Avatar class for use within the avatar mixer - encapsulates data required only for +// sorting priorities within the mixer. + +#ifndef hifi_MixerAvatar_h +#define hifi_MixerAvatar_h + +#include + +class MixerAvatar : public AvatarData { +public: + bool getPriorityAvatar() const { return _bPriorityAvatar; } + void setPriorityAvatar(bool bPriorityAvatar) { _bPriorityAvatar = bPriorityAvatar; } + +private: + bool _bPriorityAvatar { false }; +}; + +using MixerAvatarSharedPointer = std::shared_ptr; + +#endif // hifi_MixerAvatar_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 25e5893078..3ecbdf497a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1738,7 +1738,7 @@ bool EntityItem::contains(const glm::vec3& point) const { // the above cases not yet supported --> fall through to BOX case case SHAPE_TYPE_BOX: { localPoint = glm::abs(localPoint); - return glm::any(glm::lessThanEqual(localPoint, glm::vec3(NORMALIZED_HALF_SIDE))); + return glm::all(glm::lessThanEqual(localPoint, glm::vec3(NORMALIZED_HALF_SIDE))); } case SHAPE_TYPE_ELLIPSOID: { // since we've transformed into the normalized space this is just a sphere-point intersection test