Fixes for EntityItem contains test, add MixerAvatar class and use in sort

This commit is contained in:
Simon Walton 2019-02-25 15:44:52 -08:00
parent 16bc667b95
commit e5091e7f59
5 changed files with 94 additions and 35 deletions

View file

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

View file

@ -21,7 +21,7 @@
#include <QtCore/QJsonObject>
#include <QtCore/QUrl>
#include <AvatarData.h>
#include "MixerAvatar.h"
#include <AssociatedTraitValues.h>
#include <NodeData.h>
#include <NumericalConstants.h>
@ -46,10 +46,10 @@ public:
using PerNodeTraitVersions = std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions>;
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<NLPacket::LocalID, uint16_t> _lastBroadcastSequenceNumbers;

View file

@ -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<SortableAvatar>::computePriority(const SortableAvatar& thing) const {
static constexpr float AVATAR_HERO_BONUS { 25.0f }; // Higher than any normal priority.
float priority = std::numeric_limits<float>::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<NodeList>();
@ -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<SortableAvatar> 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<const AvatarMixerClientData*>(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;

View file

@ -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 <AvatarData.h>
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<MixerAvatar>;
#endif // hifi_MixerAvatar_h

View file

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