mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-05 17:19:54 +02:00
Fixes for EntityItem contains test, add MixerAvatar class and use in sort
This commit is contained in:
parent
16bc667b95
commit
e5091e7f59
5 changed files with 94 additions and 35 deletions
|
@ -135,9 +135,7 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message, const SlaveShared
|
||||||
EntityTree& entityTree = *slaveSharedData.entityTree;
|
EntityTree& entityTree = *slaveSharedData.entityTree;
|
||||||
FindPriorityZone findPriorityZone { newPosition, false } ;
|
FindPriorityZone findPriorityZone { newPosition, false } ;
|
||||||
entityTree.recurseTreeWithOperation(&FindPriorityZone::operation, &findPriorityZone);
|
entityTree.recurseTreeWithOperation(&FindPriorityZone::operation, &findPriorityZone);
|
||||||
if (findPriorityZone.isInPriorityZone) {
|
_avatar->setPriorityAvatar(findPriorityZone.isInPriorityZone);
|
||||||
// Tag avatar as hero ...
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
|
||||||
#include <AvatarData.h>
|
#include "MixerAvatar.h"
|
||||||
#include <AssociatedTraitValues.h>
|
#include <AssociatedTraitValues.h>
|
||||||
#include <NodeData.h>
|
#include <NodeData.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
@ -46,10 +46,10 @@ public:
|
||||||
using PerNodeTraitVersions = std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions>;
|
using PerNodeTraitVersions = std::unordered_map<Node::LocalID, AvatarTraits::TraitVersions>;
|
||||||
|
|
||||||
int parseData(ReceivedMessage& message, const SlaveSharedData& SlaveSharedData);
|
int parseData(ReceivedMessage& message, const SlaveSharedData& SlaveSharedData);
|
||||||
AvatarData& getAvatar() { return *_avatar; }
|
MixerAvatar& getAvatar() { return *_avatar; }
|
||||||
const AvatarData& getAvatar() const { return *_avatar; }
|
const MixerAvatar& getAvatar() const { return *_avatar; }
|
||||||
const AvatarData* getConstAvatarData() const { return _avatar.get(); }
|
const MixerAvatar* getConstAvatarData() const { return _avatar.get(); }
|
||||||
AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
MixerAvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
||||||
|
|
||||||
uint16_t getLastBroadcastSequenceNumber(NLPacket::LocalID nodeID) const;
|
uint16_t getLastBroadcastSequenceNumber(NLPacket::LocalID nodeID) const;
|
||||||
void setLastBroadcastSequenceNumber(NLPacket::LocalID nodeID, uint16_t sequenceNumber)
|
void setLastBroadcastSequenceNumber(NLPacket::LocalID nodeID, uint16_t sequenceNumber)
|
||||||
|
@ -163,7 +163,7 @@ private:
|
||||||
};
|
};
|
||||||
PacketQueue _packetQueue;
|
PacketQueue _packetQueue;
|
||||||
|
|
||||||
AvatarSharedPointer _avatar { new AvatarData() };
|
MixerAvatarSharedPointer _avatar { new MixerAvatar() };
|
||||||
|
|
||||||
uint16_t _lastReceivedSequenceNumber { 0 };
|
uint16_t _lastReceivedSequenceNumber { 0 };
|
||||||
std::unordered_map<NLPacket::LocalID, uint16_t> _lastBroadcastSequenceNumbers;
|
std::unordered_map<NLPacket::LocalID, uint16_t> _lastBroadcastSequenceNumbers;
|
||||||
|
|
|
@ -281,7 +281,51 @@ AABox computeBubbleBox(const AvatarData& avatar, float bubbleExpansionFactor) {
|
||||||
return box;
|
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) {
|
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||||
|
const float AVATAR_HERO_FRACTION { 0.4f };
|
||||||
const Node* destinationNode = node.data();
|
const Node* destinationNode = node.data();
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -314,8 +358,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
int identityBytesSent = 0;
|
int identityBytesSent = 0;
|
||||||
int traitBytesSent = 0;
|
int traitBytesSent = 0;
|
||||||
|
|
||||||
// max number of avatarBytes per frame
|
// max number of avatarBytes per frame (13 900, typical)
|
||||||
int maxAvatarBytesPerFrame = int(_maxKbpsPerNode * BYTES_PER_KILOBIT / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND);
|
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
|
// keep track of the number of other avatars held back in this frame
|
||||||
int numAvatarsHeldBack = 0;
|
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
|
const float MY_AVATAR_BUBBLE_EXPANSION_FACTOR = 4.0f; // magic number determined emperically
|
||||||
AABox nodeBox = computeBubbleBox(avatar, MY_AVATAR_BUBBLE_EXPANSION_FACTOR);
|
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
|
// prepare to sort
|
||||||
const auto& cameraViews = nodeData->getViewFrustums();
|
const auto& cameraViews = nodeData->getViewFrustums();
|
||||||
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraViews,
|
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraViews,
|
||||||
|
@ -446,7 +470,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
if (!shouldIgnore) {
|
||||||
// sort this one for later
|
// sort this one for later
|
||||||
const AvatarData* avatarNodeData = avatarClientNodeData->getConstAvatarData();
|
const MixerAvatar* avatarNodeData = avatarClientNodeData->getConstAvatarData();
|
||||||
auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNode->getLocalID());
|
auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNode->getLocalID());
|
||||||
|
|
||||||
sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
|
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();
|
auto startAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
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:
|
// Typically all out-of-view avatars but such avatars' priorities will rise with time:
|
||||||
bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD;
|
bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD;
|
||||||
|
|
31
assignment-client/src/avatars/MixerAvatar.h
Normal file
31
assignment-client/src/avatars/MixerAvatar.h
Normal 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
|
|
@ -1738,7 +1738,7 @@ bool EntityItem::contains(const glm::vec3& point) const {
|
||||||
// the above cases not yet supported --> fall through to BOX case
|
// the above cases not yet supported --> fall through to BOX case
|
||||||
case SHAPE_TYPE_BOX: {
|
case SHAPE_TYPE_BOX: {
|
||||||
localPoint = glm::abs(localPoint);
|
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: {
|
case SHAPE_TYPE_ELLIPSOID: {
|
||||||
// since we've transformed into the normalized space this is just a sphere-point intersection test
|
// since we've transformed into the normalized space this is just a sphere-point intersection test
|
||||||
|
|
Loading…
Reference in a new issue