first cut at adding view frustum support to avatar mixer

This commit is contained in:
Brad Hefta-Gaub 2016-12-13 18:58:11 -08:00
parent 92632e72b6
commit a7750501c6
9 changed files with 123 additions and 1 deletions

View file

@ -44,6 +44,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled); connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver(); auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListener(PacketType::ViewFrustum, this, "handleViewFrustumPacket");
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket"); packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
@ -275,6 +276,16 @@ void AvatarMixer::broadcastAvatarData() {
} }
// Not close enough to ignore // Not close enough to ignore
nodeData->removeFromRadiusIgnoringSet(otherNode->getUUID()); nodeData->removeFromRadiusIgnoringSet(otherNode->getUUID());
// Also check to see if the other node is in our view
glm::vec3 otherNodeBoxScale = (otherData->getPosition() - otherData->getGlobalBoundingBoxCorner()) * 2.0f;
AABox otherNodeBox(otherData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
if (!nodeData->otherAvatarInView(otherNodeBox)) {
qDebug() << "Avatar out of view!";
return false;
}
return true; return true;
} }
}, },
@ -448,6 +459,18 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
} }
} }
void AvatarMixer::handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getOrCreateLinkedData(senderNode);
if (senderNode->getLinkedData()) {
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
if (nodeData != nullptr) {
nodeData->readViewFrustumPacket(message->getMessage());
}
}
}
void AvatarMixer::handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) { void AvatarMixer::handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
nodeList->updateNodeWithDataFromPacket(message, senderNode); nodeList->updateNodeWithDataFromPacket(message, senderNode);

View file

@ -34,6 +34,7 @@ public slots:
void sendStatsPacket() override; void sendStatsPacket() override;
private slots: private slots:
void handleViewFrustumPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message); void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message);

View file

@ -57,6 +57,13 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
} }
} }
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
_currentViewFrustumIsValid = true;
_currentViewFrustum.fromByteArray(message);
qDebug() << __FUNCTION__;
_currentViewFrustum.printDebugDetails();
}
void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
jsonObject["display_name"] = _avatar->getDisplayName(); jsonObject["display_name"] = _avatar->getDisplayName();
jsonObject["full_rate_distance"] = _fullRateDistance; jsonObject["full_rate_distance"] = _fullRateDistance;

View file

@ -27,6 +27,7 @@
#include <PortableHighResolutionClock.h> #include <PortableHighResolutionClock.h>
#include <SimpleMovingAverage.h> #include <SimpleMovingAverage.h>
#include <UUIDHasher.h> #include <UUIDHasher.h>
#include <ViewFrustum.h>
const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps"; const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps";
const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps"; const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
@ -87,6 +88,12 @@ public:
void removeFromRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.erase(other); } void removeFromRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.erase(other); }
void ignoreOther(SharedNodePointer self, SharedNodePointer other); void ignoreOther(SharedNodePointer self, SharedNodePointer other);
void readViewFrustumPacket(const QByteArray& message);
bool otherAvatarInView(const AABox& otherAvatarBox) {
return !_currentViewFrustumIsValid || _currentViewFrustum.boxIntersectsKeyhole(otherAvatarBox);
}
private: private:
AvatarSharedPointer _avatar { new AvatarData() }; AvatarSharedPointer _avatar { new AvatarData() };
@ -108,6 +115,8 @@ private:
SimpleMovingAverage _avgOtherAvatarDataRate; SimpleMovingAverage _avgOtherAvatarDataRate;
std::unordered_set<QUuid> _radiusIgnoredOthers; std::unordered_set<QUuid> _radiusIgnoredOthers;
ViewFrustum _currentViewFrustum;
bool _currentViewFrustumIsValid { false };
}; };
#endif // hifi_AvatarMixerClientData_h #endif // hifi_AvatarMixerClientData_h

View file

@ -4176,6 +4176,7 @@ void Application::update(float deltaTime) {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions);
} }
sendAvatarViewFrustum();
_lastQueriedViewFrustum = _viewFrustum; _lastQueriedViewFrustum = _viewFrustum;
} }
} }
@ -4215,6 +4216,14 @@ void Application::update(float deltaTime) {
AnimDebugDraw::getInstance().update(); AnimDebugDraw::getInstance().update();
} }
void Application::sendAvatarViewFrustum() {
QByteArray viewFrustumByteArray = _viewFrustum.toByteArray();
auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size());
avatarPacket->write(viewFrustumByteArray);
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
}
int Application::sendNackPackets() { int Application::sendNackPackets() {

View file

@ -415,6 +415,7 @@ private:
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed); void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed);
int sendNackPackets(); int sendNackPackets();
void sendAvatarViewFrustum();
std::shared_ptr<MyAvatar> getMyAvatar() const; std::shared_ptr<MyAvatar> getMyAvatar() const;

View file

@ -101,7 +101,8 @@ public:
NodeKickRequest, NodeKickRequest,
NodeMuteRequest, NodeMuteRequest,
RadiusIgnoreRequest, RadiusIgnoreRequest,
LAST_PACKET_TYPE = RadiusIgnoreRequest ViewFrustum,
LAST_PACKET_TYPE = ViewFrustum
}; };
}; };

View file

@ -130,6 +130,73 @@ const char* ViewFrustum::debugPlaneName (int plane) const {
return "Unknown"; return "Unknown";
} }
void 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
const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f;
float originalFOV = cameraFov;
float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND;
if (0.0f != cameraAspectRatio &&
0.0f != cameraNearClip &&
0.0f != cameraFarClip &&
cameraNearClip != cameraFarClip) {
setProjection(glm::perspective(
glm::radians(wideFOV), // hack
cameraAspectRatio,
cameraNearClip,
cameraFarClip));
}
}
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 { ViewFrustum::intersection ViewFrustum::calculateCubeFrustumIntersection(const AACube& cube) const {
// only check against frustum // only check against frustum
ViewFrustum::intersection result = INSIDE; ViewFrustum::intersection result = INSIDE;

View file

@ -139,6 +139,10 @@ public:
const ::Plane* getPlanes() const { return _planes; } const ::Plane* getPlanes() const { return _planes; }
void invalidate(); // causes all reasonable intersection tests to fail void invalidate(); // causes all reasonable intersection tests to fail
QByteArray toByteArray();
void fromByteArray(const QByteArray& input);
private: private:
glm::mat4 _view; glm::mat4 _view;
glm::mat4 _projection; glm::mat4 _projection;