From c9c311e2751fe5aadf46e0793e0a54e4a43f49f4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 15 Jan 2017 11:47:48 -0800 Subject: [PATCH] checkpoint for distance joints --- assignment-client/src/Agent.cpp | 10 ++++- assignment-client/src/avatars/AvatarMixer.cpp | 7 ++- .../src/avatars/AvatarMixerClientData.h | 7 +++ .../src/avatars/ScriptableAvatar.cpp | 7 +++ .../src/avatars/ScriptableAvatar.h | 4 ++ interface/src/avatar/MyAvatar.cpp | 7 +-- interface/src/avatar/MyAvatar.h | 3 +- libraries/avatars/src/AvatarData.cpp | 45 +++++++++++++++---- libraries/avatars/src/AvatarData.h | 9 +++- 9 files changed, 82 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index e79085244f..2764fd4031 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -499,8 +499,14 @@ void Agent::processAgentAvatar() { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - QByteArray avatarByteArray = scriptedAvatar->toByteArray((randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) - ? AvatarData::SendAllData : AvatarData::CullSmallData); + AvatarData::AvatarDataDetail dataDetail = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? AvatarData::SendAllData : AvatarData::CullSmallData; + //AvatarData::AvatarDataDetail dataDetail = AvatarData::SendAllData; + quint64 lastSentTime = 0; + QVector& lastSentJointData = scriptedAvatar->getLastSentJointData(); + bool distanceAdjust = false; + glm::vec3 viewerPosition(0); + + QByteArray avatarByteArray = scriptedAvatar->toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); scriptedAvatar->doneEncoding(true); static AvatarDataSequenceNumber sequenceNumber = 0; diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 2c8dcb7f8a..59b8429683 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -421,8 +421,11 @@ void AvatarMixer::broadcastAvatarData() { } numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); - quint64 lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); - auto bytes = otherAvatar.toByteArray(detail, lastEncodeForOther); + auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); + auto lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); + bool distanceAdjust = true; + glm::vec3 viewerPosition = otherAvatar.getPosition(); + auto bytes = otherAvatar.toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, distanceAdjust, viewerPosition); numAvatarDataBytes += avatarPacketList->write(bytes); avatarPacketList->endSegment(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index c9306f73c7..f0b90a57bd 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -113,6 +113,12 @@ public: return result; } + QVector& getLastOtherAvatarSentJoints(QUuid otherAvatar) { + return _lastOtherAvatarSentJoints[otherAvatar]; + } + + + private: AvatarSharedPointer _avatar { new AvatarData() }; @@ -123,6 +129,7 @@ private: // this is a map of the last time we encoded an "other" avatar for // sending to "this" node std::unordered_map _lastOtherAvatarEncodeTime; + std::unordered_map> _lastOtherAvatarSentJoints; HRCTime _identityChangeTimestamp; bool _gotIdentity { false }; diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index b4c9a8e89d..989904ca7b 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -14,6 +14,13 @@ #include #include "ScriptableAvatar.h" +QByteArray ScriptableAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition) { + _globalPosition = getPosition(); + return AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); +} + + // hold and priority unused but kept so that client side JS can run. void ScriptableAvatar::startAnimation(const QString& url, float fps, float priority, bool loop, bool hold, float firstFrame, float lastFrame, const QStringList& maskedJoints) { diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 18d64f4ac5..da6c1e0b7f 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -27,6 +27,10 @@ public: Q_INVOKABLE void stopAnimation(); Q_INVOKABLE AnimationDetails getAnimationDetails(); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; + + virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition) override; + private slots: void update(float deltatime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6f5de308ac..2d1dc34b2f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -226,7 +226,8 @@ void MyAvatar::simulateAttachments(float deltaTime) { // don't update attachments here, do it in harvestResultsFromPhysicsSimulation() } -QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime) { +QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition) { CameraMode mode = qApp->getCamera()->getMode(); _globalPosition = getPosition(); _globalBoundingBoxDimensions.x = _characterController.getCapsuleRadius(); @@ -237,12 +238,12 @@ QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTi // fake the avatar position that is sent up to the AvatarMixer glm::vec3 oldPosition = getPosition(); setPosition(getSkeletonPosition()); - QByteArray array = AvatarData::toByteArray(dataDetail, lastSentTime); + QByteArray array = AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); // copy the correct position back setPosition(oldPosition); return array; } - return AvatarData::toByteArray(dataDetail, lastSentTime); + return AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); } void MyAvatar::centerBody() { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 68e65faad7..1e3b9adf5e 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -333,7 +333,8 @@ private: glm::vec3 getWorldBodyPosition() const; glm::quat getWorldBodyOrientation() const; - QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime) override; + QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition) override; void simulate(float deltaTime); void updateFromTrackers(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3f590c2ebd..3e7b087224 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -193,7 +193,17 @@ bool AvatarData::faceTrackerInfoChangedSince(quint64 time) { return true; // FIXME! } -QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime) { +float AvatarData::getDistanceBasedMinRotationDOT(glm::vec3 viewerPosition) { + return AVATAR_MIN_ROTATION_DOT; // FIXME +} + +float AvatarData::getDistanceBasedMinTranslationDistance(glm::vec3 viewerPosition) { + return AVATAR_MIN_TRANSLATION; // FIXME +} + + +QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition) { // if no timestamp was included, then assume the avatarData is single instance // and is tracking its own last encoding time. @@ -230,6 +240,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent // BUG -- if you enter a space bubble, and then back away, the avatar has wrong orientation until "send all" happens... // this is an iFrame issue... what to do about that? // + // BUG -- Resizing avatar seems to "take too long"... the avatar doesn't redraw at smaller size right away + // BUG -- summoned avatars seem low? // // TODO - @@ -242,8 +254,15 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent // 63 rotations * 6 bytes = 136kbps // 3 translations * 6 bytes = 6.48kbps // + // How we need to handle joints: + // 1) need to track "_lastSentJointData" for each "viewer" so it can't be a member variable of the + // AvatarData. instead it should be like lastSentTime where it's passed in. Store it in the node data + // and in AvatarMixer pass it accordingly + // + // 2) we also want to know the "distance" to the viewer to adjust the relative tolerance for changes and + // whether or not we actually want to do this distance adjust + // - auto localPosition = getLocalPosition(); auto parentID = getParentID(); bool hasAvatarGlobalPosition = true; // always include global position @@ -426,14 +445,16 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent unsigned char* beforeRotations = destinationBuffer; #endif - _lastSentJointData.resize(_jointData.size()); + lastSentJointData.resize(_jointData.size()); + + float minRotationDOT = !distanceAdjust ? AVATAR_MIN_ROTATION_DOT : getDistanceBasedMinRotationDOT(viewerPosition); for (int i = 0; i < _jointData.size(); i++) { const JointData& data = _jointData[i]; - if (sendAll || _lastSentJointData[i].rotation != data.rotation) { + if (sendAll || lastSentJointData[i].rotation != data.rotation) { if (sendAll || !cullSmallChanges || - fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) { + fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) <= minRotationDOT) { if (data.rotationSet) { validity |= (1 << validityBit); #if 1 //def WANT_DEBUG @@ -475,13 +496,15 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent unsigned char* beforeTranslations = destinationBuffer; #endif + float minTranslation = !distanceAdjust ? AVATAR_MIN_TRANSLATION : getDistanceBasedMinTranslationDistance(viewerPosition); + float maxTranslationDimension = 0.0; for (int i = 0; i < _jointData.size(); i++) { const JointData& data = _jointData[i]; - if (sendAll || _lastSentJointData[i].translation != data.translation) { + if (sendAll || lastSentJointData[i].translation != data.translation) { if (sendAll || !cullSmallChanges || - glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) { + glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) { if (data.translationSet) { validity |= (1 << validityBit); #if 1 //def WANT_DEBUG @@ -1508,7 +1531,13 @@ void AvatarData::sendAvatarDataPacket() { // about 2% of the time, we send a full update (meaning, we transmit all the joint data), even if nothing has changed. // this is to guard against a joint moving once, the packet getting lost, and the joint never moving again. - QByteArray avatarByteArray = toByteArray((randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? SendAllData : CullSmallData); + + auto dataDetail = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? SendAllData : CullSmallData; + quint64 lastSentTime = 0; + QVector& lastSentJointData = _lastSentJointData; + bool distanceAdjust = false; + glm::vec3 viewerPosition(0); + QByteArray avatarByteArray = toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); doneEncoding(true); // FIXME - doneEncoding() takes a bool for culling small changes, that's janky! diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 433c5441eb..5652ccd705 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -347,7 +347,9 @@ public: SendAllData } AvatarDataDetail; - virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime = 0); + virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition); + virtual void doneEncoding(bool cullSmallChanges); /// \return true if an error should be logged @@ -526,6 +528,8 @@ public: float getDataRate(const QString& rateName = QString("")); + QVector& getLastSentJointData() { return _lastSentJointData; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -545,6 +549,9 @@ public slots: protected: void lazyInitHeadData(); + float getDistanceBasedMinRotationDOT(glm::vec3 viewerPosition); + float getDistanceBasedMinTranslationDistance(glm::vec3 viewerPosition); + bool avatarBoundingBoxChangedSince(quint64 time); bool avatarScaleChangedSince(quint64 time); bool lookAtPositionChangedSince(quint64 time);