diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 32cecd3801..ad29cee75c 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -507,6 +507,7 @@ void Agent::processAgentAvatar() { 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 ab9d024556..9dd9f76adf 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -422,10 +422,10 @@ void AvatarMixer::broadcastAvatarData() { numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); - auto lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); + QVector& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); bool distanceAdjust = true; glm::vec3 viewerPosition = nodeData->getPosition(); - auto bytes = otherAvatar.toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, distanceAdjust, viewerPosition); + auto bytes = otherAvatar.toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, distanceAdjust, viewerPosition, &lastSentJointsForOther); numAvatarDataBytes += avatarPacketList->write(bytes); avatarPacketList->endSegment(); diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index d4d5b470b8..eccc140f32 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -14,8 +14,8 @@ #include #include "ScriptableAvatar.h" -QByteArray ScriptableAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, - bool distanceAdjust, glm::vec3 viewerPosition) { +QByteArray ScriptableAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut) { _globalPosition = getPosition(); return AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); } diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index da6c1e0b7f..59f47a9ebb 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -28,8 +28,8 @@ public: 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; + virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut = nullptr) override; private slots: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2d1dc34b2f..acc920dc86 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -226,8 +226,8 @@ void MyAvatar::simulateAttachments(float deltaTime) { // don't update attachments here, do it in harvestResultsFromPhysicsSimulation() } -QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, - bool distanceAdjust, glm::vec3 viewerPosition) { +QByteArray MyAvatar::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut) { CameraMode mode = qApp->getCamera()->getMode(); _globalPosition = getPosition(); _globalBoundingBoxDimensions.x = _characterController.getCapsuleRadius(); @@ -238,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, lastSentJointData, distanceAdjust, viewerPosition); + QByteArray array = AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition, sentJointDataOut); // copy the correct position back setPosition(oldPosition); return array; } - return AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition); + return AvatarData::toByteArray(dataDetail, lastSentTime, lastSentJointData, distanceAdjust, viewerPosition, sentJointDataOut); } void MyAvatar::centerBody() { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1e3b9adf5e..bb591afd51 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -333,8 +333,11 @@ private: glm::vec3 getWorldBodyPosition() const; glm::quat getWorldBodyOrientation() const; - QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, - bool distanceAdjust, glm::vec3 viewerPosition) override; + + + virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut = nullptr) 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 e7262bb38c..c31fdfbdb6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -196,15 +196,18 @@ bool AvatarData::faceTrackerInfoChangedSince(quint64 time) { float AvatarData::getDistanceBasedMinRotationDOT(glm::vec3 viewerPosition) { auto distance = glm::distance(_globalPosition, viewerPosition); //qDebug() << "_globalPosition:" << _globalPosition << "viewerPosition:" << viewerPosition << "distance:" << distance; - float result = ROTATION_90D_DOT; // assume worst + float result = ROTATION_179D_DOT; // assume worst if (distance < 1.0f) { result = AVATAR_MIN_ROTATION_DOT; } else if (distance < 5.0f) { result = ROTATION_15D_DOT; } else if (distance < 10.0f) { result = ROTATION_45D_DOT; + } else if (distance < 20.0f) { + result = ROTATION_90D_DOT; } //qDebug() << __FUNCTION__ << "result:" << result; + return result; } @@ -213,8 +216,8 @@ float AvatarData::getDistanceBasedMinTranslationDistance(glm::vec3 viewerPositio } -QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, - bool distanceAdjust, glm::vec3 viewerPosition) { +QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut) { // if no timestamp was included, then assume the avatarData is single instance // and is tracking its own last encoding time. @@ -455,25 +458,43 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent unsigned char* beforeRotations = destinationBuffer; #endif - lastSentJointData.resize(_jointData.size()); - + if (sentJointDataOut) { + if (sentJointDataOut->size() != _jointData.size()) { + sentJointDataOut->resize(_jointData.size()); + } + } float minRotationDOT = !distanceAdjust ? AVATAR_MIN_ROTATION_DOT : getDistanceBasedMinRotationDOT(viewerPosition); - //qDebug() << "sendAll:" << sendAll << "cullSmallChanges:" << cullSmallChanges; + auto distance = glm::distance(_globalPosition, viewerPosition); + //qDebug() << "sendAll:" << sendAll << "cullSmallChanges:" << cullSmallChanges << "minRotationDOT:" << minRotationDOT << "distance:" << distance; for (int i = 0; i < _jointData.size(); i++) { const JointData& data = _jointData[i]; - //qDebug() << "joint[" << i << "].dot:" << fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)); + // The dot product for smaller rotations is a smaller number. + // + // const float AVATAR_MIN_ROTATION_DOT = 0.9999999f; + // const float ROTATION_15D_DOT = 0.9914449f; + // const float ROTATION_45D_DOT = 0.9238795f; + // const float ROTATION_90D_DOT = 0.7071068f; + // So if the dot() is less than the value, then the rotation is a larger angle of rotation + // + bool largeEnoughRotation = fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) < minRotationDOT; + + //qDebug() << "joint[" << i << "].dot:" << fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) << "minRotationDOT:" << minRotationDOT << "largeEnoughRotation:" << largeEnoughRotation; + if (sendAll || lastSentJointData[i].rotation != data.rotation) { - if (sendAll || - !cullSmallChanges || - fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) > minRotationDOT) { + if (sendAll || !cullSmallChanges || largeEnoughRotation) { if (data.rotationSet) { validity |= (1 << validityBit); #if 1 //def WANT_DEBUG rotationSentCount++; #endif + if (sentJointDataOut) { + auto jointDataOut = *sentJointDataOut; + jointDataOut[i].rotation = data.rotation; + } + } } } @@ -527,6 +548,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension); maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension); maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension); + + if (sentJointDataOut) { + auto jointDataOut = *sentJointDataOut; + jointDataOut[i].translation = data.translation; + } + } } } @@ -585,6 +612,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent return avatarDataByteArray.left(avatarDataSize); } +// NOTE: This is never used in a "distanceAdjust" mode, so it's ok that it doesn't use a variable minimum rotation/translation void AvatarData::doneEncoding(bool cullSmallChanges) { // The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData. QReadLocker readLock(&_jointDataLock); @@ -1549,14 +1577,19 @@ 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. - auto dataDetail = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? SendAllData : CullSmallData; + bool cullSmallData = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); + auto dataDetail = cullSmallData ? SendAllData : CullSmallData; quint64 lastSentTime = 0; - QVector& lastSentJointData = _lastSentJointData; + QVector lastSentJointData; + { + QReadLocker readLock(&_jointDataLock); + 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! + doneEncoding(cullSmallData); // FIXME - doneEncoding() takes a bool for culling small changes, that's janky! static AvatarDataSequenceNumber sequenceNumber = 0; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cfac697df3..bd0591973a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -260,7 +260,8 @@ const float AVATAR_MIN_TRANSLATION = 0.0001f; const float ROTATION_15D_DOT = 0.9914449f; const float ROTATION_45D_DOT = 0.9238795f; -const float ROTATION_90D_DOT = 0.7071068f; +const float ROTATION_90D_DOT = 0.7071068f; +const float ROTATION_179D_DOT = 0.0087266f; // Where one's own Avatar begins in the world (will be overwritten if avatar data file is found). // This is the start location in the Sandbox (xyz: 6270, 211, 6000). @@ -350,8 +351,8 @@ public: SendAllData } AvatarDataDetail; - virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, QVector& lastSentJointData, - bool distanceAdjust, glm::vec3 viewerPosition); + virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector& lastSentJointData, + bool distanceAdjust, glm::vec3 viewerPosition, QVector* sentJointDataOut = nullptr); virtual void doneEncoding(bool cullSmallChanges); @@ -531,7 +532,11 @@ public: float getDataRate(const QString& rateName = QString("")); - QVector& getLastSentJointData() { return _lastSentJointData; } + QVector getLastSentJointData() { + QReadLocker readLock(&_jointDataLock); + return _lastSentJointData; + } + public slots: void sendAvatarDataPacket();