Added defaultPoseFlags to avatar protocol

Change rotationSet to rotationIsDefaultPose for JointData
Also for translation.  Fixed all code to flip boolean value.
Created EntityJointData so that the ModelEntity stuff doesn't need to change.
This commit is contained in:
Anthony J. Thibault 2018-01-18 13:43:55 -08:00
parent c5efcf5d6a
commit cd4d9255bd
12 changed files with 234 additions and 77 deletions

View file

@ -123,12 +123,12 @@ void ScriptableAvatar::update(float deltatime) {
AnimPose& absPose = absPoses[i]; AnimPose& absPose = absPoses[i];
if (data.rotation != absPose.rot()) { if (data.rotation != absPose.rot()) {
data.rotation = absPose.rot(); data.rotation = absPose.rot();
data.rotationSet = true; data.rotationIsDefaultPose = false;
} }
AnimPose& relPose = poses[i]; AnimPose& relPose = poses[i];
if (data.translation != relPose.trans()) { if (data.translation != relPose.trans()) {
data.translation = relPose.trans(); data.translation = relPose.trans();
data.translationSet = true; data.translationIsDefaultPose = false;
} }
} }

View file

@ -566,9 +566,9 @@ void ModelOverlay::animate() {
rotationMat * fbxJoints[index].postTransform); rotationMat * fbxJoints[index].postTransform);
auto& jointData = jointsData[j]; auto& jointData = jointsData[j];
jointData.translation = extractTranslation(finalMat); jointData.translation = extractTranslation(finalMat);
jointData.translationSet = true; jointData.translationIsDefaultPose = false;
jointData.rotation = glmExtractRotation(finalMat); jointData.rotation = glmExtractRotation(finalMat);
jointData.rotationSet = true; jointData.rotationIsDefaultPose = false;
} }
} }
// Set the data in the model // Set the data in the model

View file

@ -1705,16 +1705,16 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
// rotations are in absolute rig frame. // rotations are in absolute rig frame.
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot(); glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
data.rotation = _internalPoseSet._absolutePoses[i].rot(); data.rotation = _internalPoseSet._absolutePoses[i].rot();
data.rotationSet = !isEqual(data.rotation, defaultAbsRot); data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
// translations are in relative frame but scaled so that they are in meters, // translations are in relative frame but scaled so that they are in meters,
// instead of geometry units. // instead of geometry units.
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans(); glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans(); data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
data.translationSet = !isEqual(data.translation, defaultRelTrans); data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
} else { } else {
data.translationSet = false; data.translationIsDefaultPose = true;
data.rotationSet = false; data.rotationIsDefaultPose = true;
} }
} }
} }
@ -1739,11 +1739,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform)); const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
for (int i = 0; i < numJoints; i++) { for (int i = 0; i < numJoints; i++) {
const JointData& data = jointDataVec.at(i); const JointData& data = jointDataVec.at(i);
if (data.rotationSet) { if (data.rotationIsDefaultPose) {
rotations.push_back(absoluteDefaultPoses[i].rot());
} else {
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame // JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
rotations.push_back(rigToGeometryRot * data.rotation); rotations.push_back(rigToGeometryRot * data.rotation);
} else {
rotations.push_back(absoluteDefaultPoses[i].rot());
} }
} }
@ -1759,11 +1759,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
const JointData& data = jointDataVec.at(i); const JointData& data = jointDataVec.at(i);
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE; _internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
_internalPoseSet._relativePoses[i].rot() = rotations[i]; _internalPoseSet._relativePoses[i].rot() = rotations[i];
if (data.translationSet) { if (data.translationIsDefaultPose) {
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
} else {
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame // JointData translations are in scaled relative-frame so we scale back to regular relative-frame
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation; _internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
} else {
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
} }
} }
} }

View file

@ -39,6 +39,7 @@
#include <AudioHelpers.h> #include <AudioHelpers.h>
#include <Profile.h> #include <Profile.h>
#include <VariantMapToScriptValue.h> #include <VariantMapToScriptValue.h>
#include <BitVectorHelpers.h>
#include "AvatarLogging.h" #include "AvatarLogging.h"
@ -77,6 +78,12 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints) {
return totalSize; return totalSize;
} }
size_t AvatarDataPacket::maxJointDefaultPoseFlagsSize(size_t numJoints) {
const size_t bitVectorSize = calcBitVectorSize((int)numJoints);
size_t totalSize = sizeof(uint8_t); // numJoints
totalSize += 2 * bitVectorSize;
return totalSize;
}
AvatarData::AvatarData() : AvatarData::AvatarData() :
SpatiallyNestable(NestableType::Avatar, QUuid()), SpatiallyNestable(NestableType::Avatar, QUuid()),
@ -272,6 +279,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
bool hasFaceTrackerInfo = false; bool hasFaceTrackerInfo = false;
bool hasJointData = false; bool hasJointData = false;
bool hasJointDefaultPoseFlags = false;
if (sendPALMinimum) { if (sendPALMinimum) {
hasAudioLoudness = true; hasAudioLoudness = true;
@ -290,6 +298,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime)); hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
hasJointData = sendAll || !sendMinimum; hasJointData = sendAll || !sendMinimum;
hasJointDefaultPoseFlags = hasJointData;
} }
@ -314,7 +323,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
| (hasParentInfo ? AvatarDataPacket::PACKET_HAS_PARENT_INFO : 0) | (hasParentInfo ? AvatarDataPacket::PACKET_HAS_PARENT_INFO : 0)
| (hasAvatarLocalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION : 0) | (hasAvatarLocalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION : 0)
| (hasFaceTrackerInfo ? AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO : 0) | (hasFaceTrackerInfo ? AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO : 0)
| (hasJointData ? AvatarDataPacket::PACKET_HAS_JOINT_DATA : 0); | (hasJointData ? AvatarDataPacket::PACKET_HAS_JOINT_DATA : 0)
| (hasJointDefaultPoseFlags ? AvatarDataPacket::PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS : 0);
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags)); memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
destinationBuffer += sizeof(packetStateFlags); destinationBuffer += sizeof(packetStateFlags);
@ -541,14 +551,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
for (int i = 0; i < _jointData.size(); i++) { for (int i = 0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i]; const JointData& data = _jointData[i];
const JointData& last = lastSentJointData[i];
// The dot product for smaller rotations is a smaller number. if (!data.rotationIsDefaultPose) {
// So if the dot() is less than the value, then the rotation is a larger angle of rotation if (sendAll || last.rotationIsDefaultPose || last.rotation != data.rotation) {
bool largeEnoughRotation = fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) < minRotationDOT;
if (sendAll || lastSentJointData[i].rotation != data.rotation) { bool largeEnoughRotation = true;
if (sendAll || !cullSmallChanges || largeEnoughRotation) { if (cullSmallChanges) {
if (data.rotationSet) { // The dot product for smaller rotations is a smaller number.
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
largeEnoughRotation = fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT;
}
if (sendAll || !cullSmallChanges || largeEnoughRotation) {
validity |= (1 << validityBit); validity |= (1 << validityBit);
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
rotationSentCount++; rotationSentCount++;
@ -557,8 +572,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (sentJointDataOut) { if (sentJointDataOut) {
localSentJointDataOut[i].rotation = data.rotation; localSentJointDataOut[i].rotation = data.rotation;
localSentJointDataOut[i].rotationIsDefaultPose = false;
} }
} }
} }
} }
@ -588,11 +603,10 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
float maxTranslationDimension = 0.0; float maxTranslationDimension = 0.0;
for (int i = 0; i < _jointData.size(); i++) { for (int i = 0; i < _jointData.size(); i++) {
const JointData& data = _jointData[i]; const JointData& data = _jointData[i];
if (sendAll || lastSentJointData[i].translation != data.translation) {
if (sendAll || if (!data.translationIsDefaultPose) {
!cullSmallChanges || if (sendAll || lastSentJointData[i].translation != data.translation) {
glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) { if (sendAll || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
if (data.translationSet) {
validity |= (1 << validityBit); validity |= (1 << validityBit);
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
translationSentCount++; translationSentCount++;
@ -606,8 +620,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (sentJointDataOut) { if (sentJointDataOut) {
localSentJointDataOut[i].translation = data.translation; localSentJointDataOut[i].translation = data.translation;
localSentJointDataOut[i].translationIsDefaultPose = false;
} }
} }
} }
} }
@ -655,6 +669,30 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
} }
} }
if (hasJointDefaultPoseFlags) {
auto startSection = destinationBuffer;
QReadLocker readLock(&_jointDataLock);
// write numJoints
int numJoints = _jointData.size();
*destinationBuffer++ = (uint8_t)numJoints;
// write rotationIsDefaultPose bits
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
return _jointData[i].rotationIsDefaultPose;
});
// write translationIsDefaultPose bits
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
return _jointData[i].translationIsDefaultPose;
});
if (outboundDataRateOut) {
size_t numBytes = destinationBuffer - startSection;
outboundDataRateOut->jointDefaultPoseFlagsRate.increment(numBytes);
}
}
int avatarDataSize = destinationBuffer - startPosition; int avatarDataSize = destinationBuffer - startPosition;
if (avatarDataSize > (int)byteArraySize) { if (avatarDataSize > (int)byteArraySize) {
@ -664,6 +702,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
return avatarDataByteArray.left(avatarDataSize); 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 // 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) { void AvatarData::doneEncoding(bool cullSmallChanges) {
// The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData. // The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData.
@ -674,7 +713,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
if (_lastSentJointData[i].rotation != data.rotation) { if (_lastSentJointData[i].rotation != data.rotation) {
if (!cullSmallChanges || if (!cullSmallChanges ||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) { fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
if (data.rotationSet) { if (!data.rotationIsDefaultPose) {
_lastSentJointData[i].rotation = data.rotation; _lastSentJointData[i].rotation = data.rotation;
} }
} }
@ -682,7 +721,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
if (_lastSentJointData[i].translation != data.translation) { if (_lastSentJointData[i].translation != data.translation) {
if (!cullSmallChanges || if (!cullSmallChanges ||
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) { glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
if (data.translationSet) { if (!data.translationIsDefaultPose) {
_lastSentJointData[i].translation = data.translation; _lastSentJointData[i].translation = data.translation;
} }
} }
@ -730,6 +769,7 @@ const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSa
// read data in packet starting at byte offset and return number of bytes parsed // read data in packet starting at byte offset and return number of bytes parsed
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
// lazily allocate memory for HeadData in case we're not an Avatar instance // lazily allocate memory for HeadData in case we're not an Avatar instance
lazyInitHeadData(); lazyInitHeadData();
@ -745,18 +785,19 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
#define HAS_FLAG(B,F) ((B & F) == F) #define HAS_FLAG(B,F) ((B & F) == F)
bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION); bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION);
bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX); bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX);
bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION); bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION);
bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE); bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE);
bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION); bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION);
bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS); bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS);
bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX); bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX);
bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS); bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS);
bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO); bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO);
bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION); bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION);
bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO); bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO);
bool hasJointData = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DATA); bool hasJointData = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DATA);
bool hasJointDefaultPoseFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS);
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
@ -1055,7 +1096,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
if (validRotations[i]) { if (validRotations[i]) {
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation); sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation);
_hasNewJointData = true; _hasNewJointData = true;
data.rotationSet = true; data.rotationIsDefaultPose = false;
} }
} }
@ -1090,7 +1131,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
if (validTranslations[i]) { if (validTranslations[i]) {
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX); sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
_hasNewJointData = true; _hasNewJointData = true;
data.translationSet = true; data.translationIsDefaultPose = false;
} }
} }
@ -1110,6 +1151,32 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
_jointDataUpdateRate.increment(); _jointDataUpdateRate.increment();
} }
if (hasJointDefaultPoseFlags) {
auto startSection = sourceBuffer;
QWriteLocker writeLock(&_jointDataLock);
PACKET_READ_CHECK(JointDefaultPoseFlagsNumJoints, sizeof(uint8_t));
int numJoints = (int)*sourceBuffer++;
_jointData.resize(numJoints);
size_t bitVectorSize = calcBitVectorSize(numJoints);
PACKET_READ_CHECK(JointDefaultPoseFlagsRotationFlags, bitVectorSize);
sourceBuffer += readBitVector(sourceBuffer, numJoints, [&](int i, bool value) {
_jointData[i].rotationIsDefaultPose = value;
});
PACKET_READ_CHECK(JointDefaultPoseFlagsTranslationFlags, bitVectorSize);
sourceBuffer += readBitVector(sourceBuffer, numJoints, [&](int i, bool value) {
_jointData[i].translationIsDefaultPose = value;
});
int numBytesRead = sourceBuffer - startSection;
_jointDefaultPoseFlagsRate.increment(numBytesRead);
_jointDefaultPoseFlagsUpdateRate.increment();
}
int numBytesRead = sourceBuffer - startPosition; int numBytesRead = sourceBuffer - startPosition;
_averageBytesReceived.updateAverage(numBytesRead); _averageBytesReceived.updateAverage(numBytesRead);
@ -1146,6 +1213,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
return _faceTrackerRate.rate() / BYTES_PER_KILOBIT; return _faceTrackerRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "jointData") { } else if (rateName == "jointData") {
return _jointDataRate.rate() / BYTES_PER_KILOBIT; return _jointDataRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "jointDefaultPoseFlagsRate") {
return _jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "globalPositionOutbound") { } else if (rateName == "globalPositionOutbound") {
return _outboundDataRate.globalPositionRate.rate() / BYTES_PER_KILOBIT; return _outboundDataRate.globalPositionRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "localPositionOutbound") { } else if (rateName == "localPositionOutbound") {
@ -1170,6 +1239,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
return _outboundDataRate.faceTrackerRate.rate() / BYTES_PER_KILOBIT; return _outboundDataRate.faceTrackerRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "jointDataOutbound") { } else if (rateName == "jointDataOutbound") {
return _outboundDataRate.jointDataRate.rate() / BYTES_PER_KILOBIT; return _outboundDataRate.jointDataRate.rate() / BYTES_PER_KILOBIT;
} else if (rateName == "jointDefaultPoseFlagsOutbound") {
return _outboundDataRate.jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
} }
return 0.0f; return 0.0f;
} }
@ -1236,9 +1307,9 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v
} }
JointData& data = _jointData[index]; JointData& data = _jointData[index];
data.rotation = rotation; data.rotation = rotation;
data.rotationSet = true; data.rotationIsDefaultPose = false;
data.translation = translation; data.translation = translation;
data.translationSet = true; data.translationIsDefaultPose = false;
} }
void AvatarData::clearJointData(int index) { void AvatarData::clearJointData(int index) {
@ -1294,7 +1365,8 @@ void AvatarData::setJointData(const QString& name, const glm::quat& rotation, co
auto& jointData = _jointData[index]; auto& jointData = _jointData[index];
jointData.rotation = rotation; jointData.rotation = rotation;
jointData.translation = translation; jointData.translation = translation;
jointData.rotationSet = jointData.translationSet = true; jointData.rotationIsDefaultPose = false;
jointData.translationIsDefaultPose = false;
}); });
} }
@ -1304,7 +1376,7 @@ void AvatarData::setJointRotation(const QString& name, const glm::quat& rotation
writeLockWithNamedJointIndex(name, [&](int index) { writeLockWithNamedJointIndex(name, [&](int index) {
auto& data = _jointData[index]; auto& data = _jointData[index];
data.rotation = rotation; data.rotation = rotation;
data.rotationSet = true; data.rotationIsDefaultPose = false;
}); });
} }
@ -1314,7 +1386,7 @@ void AvatarData::setJointTranslation(const QString& name, const glm::vec3& trans
writeLockWithNamedJointIndex(name, [&](int index) { writeLockWithNamedJointIndex(name, [&](int index) {
auto& data = _jointData[index]; auto& data = _jointData[index];
data.translation = translation; data.translation = translation;
data.translationSet = true; data.translationIsDefaultPose = false;
}); });
} }
@ -1328,7 +1400,7 @@ void AvatarData::setJointRotation(int index, const glm::quat& rotation) {
} }
JointData& data = _jointData[index]; JointData& data = _jointData[index];
data.rotation = rotation; data.rotation = rotation;
data.rotationSet = true; data.rotationIsDefaultPose = false;
} }
void AvatarData::setJointTranslation(int index, const glm::vec3& translation) { void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
@ -1341,7 +1413,7 @@ void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
} }
JointData& data = _jointData[index]; JointData& data = _jointData[index];
data.translation = translation; data.translation = translation;
data.translationSet = true; data.translationIsDefaultPose = false;
} }
void AvatarData::clearJointData(const QString& name) { void AvatarData::clearJointData(const QString& name) {
@ -1397,7 +1469,7 @@ void AvatarData::setJointRotations(const QVector<glm::quat>& jointRotations) {
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
auto& data = _jointData[i]; auto& data = _jointData[i];
data.rotation = jointRotations[i]; data.rotation = jointRotations[i];
data.rotationSet = true; data.rotationIsDefaultPose = false;
} }
} }
@ -1419,7 +1491,7 @@ void AvatarData::setJointTranslations(const QVector<glm::vec3>& jointTranslation
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
auto& data = _jointData[i]; auto& data = _jointData[i];
data.translation = jointTranslations[i]; data.translation = jointTranslations[i];
data.translationSet = true; data.translationIsDefaultPose = false;
} }
} }
@ -1996,9 +2068,9 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
if (json.isArray()) { if (json.isArray()) {
QJsonArray array = json.toArray(); QJsonArray array = json.toArray();
result.rotation = quatFromJsonValue(array[0]); result.rotation = quatFromJsonValue(array[0]);
result.rotationSet = true; result.rotationIsDefaultPose = false;
result.translation = vec3FromJsonValue(array[1]); result.translation = vec3FromJsonValue(array[1]);
result.translationSet = true; result.translationIsDefaultPose = false;
} }
return result; return result;
} }

View file

@ -113,18 +113,19 @@ namespace AvatarDataPacket {
// Packet State Flags - we store the details about the existence of other records in this bitset: // Packet State Flags - we store the details about the existence of other records in this bitset:
// AvatarGlobalPosition, Avatar face tracker, eye tracking, and existence of // AvatarGlobalPosition, Avatar face tracker, eye tracking, and existence of
using HasFlags = uint16_t; using HasFlags = uint16_t;
const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0; const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0;
const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1; const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1;
const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2; const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2;
const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3; const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3;
const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4; const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4;
const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5; const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5;
const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6; const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6;
const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7; const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7;
const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8; const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8;
const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9; const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9;
const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10; const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10;
const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11; const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11;
const HasFlags PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS = 1U << 12;
const size_t AVATAR_HAS_FLAGS_SIZE = 2; const size_t AVATAR_HAS_FLAGS_SIZE = 2;
using SixByteQuat = uint8_t[6]; using SixByteQuat = uint8_t[6];
@ -256,6 +257,15 @@ namespace AvatarDataPacket {
}; };
*/ */
size_t maxJointDataSize(size_t numJoints); size_t maxJointDataSize(size_t numJoints);
/*
struct JointDefaultPoseFlags {
uint8_t numJoints;
uint8_t rotationIsDefaultPoseBits[ceil(numJoints / 8)];
uint8_t translationIsDefaultPoseBits[ceil(numJoints / 8)];
};
*/
size_t maxJointDefaultPoseFlagsSize(size_t numJoints);
} }
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
@ -321,6 +331,7 @@ public:
RateCounter<> parentInfoRate; RateCounter<> parentInfoRate;
RateCounter<> faceTrackerRate; RateCounter<> faceTrackerRate;
RateCounter<> jointDataRate; RateCounter<> jointDataRate;
RateCounter<> jointDefaultPoseFlagsRate;
}; };
class AvatarPriority { class AvatarPriority {
@ -810,6 +821,7 @@ protected:
RateCounter<> _parentInfoRate; RateCounter<> _parentInfoRate;
RateCounter<> _faceTrackerRate; RateCounter<> _faceTrackerRate;
RateCounter<> _jointDataRate; RateCounter<> _jointDataRate;
RateCounter<> _jointDefaultPoseFlagsRate;
// Some rate data for incoming data updates // Some rate data for incoming data updates
RateCounter<> _parseBufferUpdateRate; RateCounter<> _parseBufferUpdateRate;
@ -825,6 +837,7 @@ protected:
RateCounter<> _parentInfoUpdateRate; RateCounter<> _parentInfoUpdateRate;
RateCounter<> _faceTrackerUpdateRate; RateCounter<> _faceTrackerUpdateRate;
RateCounter<> _jointDataUpdateRate; RateCounter<> _jointDataUpdateRate;
RateCounter<> _jointDefaultPoseFlagsUpdateRate;
// Some rate data for outgoing data // Some rate data for outgoing data
AvatarDataRate _outboundDataRate; AvatarDataRate _outboundDataRate;

View file

@ -1050,7 +1050,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
return; return;
} }
QVector<JointData> jointsData; QVector<EntityJointData> jointsData;
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
int frameCount = frames.size(); int frameCount = frames.size();

View file

@ -452,7 +452,7 @@ void ModelEntityItem::resizeJointArrays(int newSize) {
}); });
} }
void ModelEntityItem::setAnimationJointsData(const QVector<JointData>& jointsData) { void ModelEntityItem::setAnimationJointsData(const QVector<EntityJointData>& jointsData) {
resizeJointArrays(jointsData.size()); resizeJointArrays(jointsData.size());
_jointDataLock.withWriteLock([&] { _jointDataLock.withWriteLock([&] {
for (auto index = 0; index < jointsData.size(); ++index) { for (auto index = 0; index < jointsData.size(); ++index) {

View file

@ -124,7 +124,7 @@ public:
virtual void setJointTranslations(const QVector<glm::vec3>& translations); virtual void setJointTranslations(const QVector<glm::vec3>& translations);
virtual void setJointTranslationsSet(const QVector<bool>& translationsSet); virtual void setJointTranslationsSet(const QVector<bool>& translationsSet);
virtual void setAnimationJointsData(const QVector<JointData>& jointsData); virtual void setAnimationJointsData(const QVector<EntityJointData>& jointsData);
QVector<glm::quat> getJointRotations() const; QVector<glm::quat> getJointRotations() const;
QVector<bool> getJointRotationsSet() const; QVector<bool> getJointRotationsSet() const;
@ -150,7 +150,7 @@ protected:
bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations
struct ModelJointData { struct ModelJointData {
JointData joint; EntityJointData joint;
bool rotationDirty { false }; bool rotationDirty { false };
bool translationDirty { false }; bool translationDirty { false };
}; };

View file

@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::AvatarData: case PacketType::AvatarData:
case PacketType::BulkAvatarData: case PacketType::BulkAvatarData:
case PacketType::KillAvatar: case PacketType::KillAvatar:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::UpdatedMannequinDefaultAvatar); return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarJointDefaultPoseFlags);
case PacketType::MessagesData: case PacketType::MessagesData:
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData); return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
case PacketType::ICEServerHeartbeat: case PacketType::ICEServerHeartbeat:

View file

@ -247,7 +247,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
AvatarIdentitySequenceFront, AvatarIdentitySequenceFront,
IsReplicatedInAvatarIdentity, IsReplicatedInAvatarIdentity,
AvatarIdentityLookAtSnapping, AvatarIdentityLookAtSnapping,
UpdatedMannequinDefaultAvatar UpdatedMannequinDefaultAvatar,
AvatarJointDefaultPoseFlags
}; };
enum class DomainConnectRequestVersion : PacketVersion { enum class DomainConnectRequestVersion : PacketVersion {

View file

@ -0,0 +1,58 @@
//
// BitVectorHelpers.h
// libraries/shared/src
//
// Created by Anthony Thibault on 1/19/18.
// Copyright 2018 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
//
#ifndef hifi_BitVectorHelpers_h
#define hifi_BitVectorHelpers_h
size_t calcBitVectorSize(int numBits) {
return ((numBits - 1) >> 3) + 1;
}
// func should be of type bool func(int index)
template <typename F>
size_t writeBitVector(uint8_t* destinationBuffer, int numBits, const F& func) {
size_t totalBytes = ((numBits - 1) >> 3) + 1;
uint8_t* cursor = destinationBuffer;
uint8_t byte = 0;
uint8_t bit = 0;
for (int i = 0; i < numBits; i++) {
if (func(i)) {
byte |= (1 << bit);
}
if (++bit == BITS_IN_BYTE) {
*cursor++ = byte;
byte = 0;
bit = 0;
}
}
return totalBytes;
}
// func should be of type 'void func(int index, bool value)'
template <typename F>
size_t readBitVector(const uint8_t* sourceBuffer, int numBits, const F& func) {
size_t totalBytes = ((numBits - 1) >> 3) + 1;
const uint8_t* cursor = sourceBuffer;
uint8_t bit = 0;
for (int i = 0; i < numBits; i++) {
bool value = (bool)(*cursor & (1 << bit));
func(i, value);
if (++bit == BITS_IN_BYTE) {
cursor++;
bit = 0;
}
}
return totalBytes;
}
#endif

View file

@ -5,14 +5,27 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
// Used by the avatar mixer to describe a single joint class EntityJointData {
// These are relative to their parent and translations are in meters
class JointData {
public: public:
glm::quat rotation; glm::quat rotation;
glm::vec3 translation;
bool rotationSet = false; bool rotationSet = false;
glm::vec3 translation; // meters
bool translationSet = false; bool translationSet = false;
}; };
// Used by the avatar mixer to describe a single joint
// Translations relative to their parent and are in meters.
// Rotations are absolute (i.e. not relative to parent) and are in rig space.
class JointData {
public:
glm::quat rotation;
glm::vec3 translation;
// This indicates that the rotation or translation is the same as the defaultPose for the avatar.
// if true, it also means that the rotation or translation value in this structure is not valid and
// should be replaced by the avatar's actual default pose value.
bool rotationIsDefaultPose = true;
bool translationIsDefaultPose = true;
};
#endif #endif