mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
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:
parent
c5efcf5d6a
commit
cd4d9255bd
12 changed files with 234 additions and 77 deletions
|
@ -123,12 +123,12 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
AnimPose& absPose = absPoses[i];
|
||||
if (data.rotation != absPose.rot()) {
|
||||
data.rotation = absPose.rot();
|
||||
data.rotationSet = true;
|
||||
data.rotationIsDefaultPose = false;
|
||||
}
|
||||
AnimPose& relPose = poses[i];
|
||||
if (data.translation != relPose.trans()) {
|
||||
data.translation = relPose.trans();
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -566,9 +566,9 @@ void ModelOverlay::animate() {
|
|||
rotationMat * fbxJoints[index].postTransform);
|
||||
auto& jointData = jointsData[j];
|
||||
jointData.translation = extractTranslation(finalMat);
|
||||
jointData.translationSet = true;
|
||||
jointData.translationIsDefaultPose = false;
|
||||
jointData.rotation = glmExtractRotation(finalMat);
|
||||
jointData.rotationSet = true;
|
||||
jointData.rotationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
// Set the data in the model
|
||||
|
|
|
@ -1705,16 +1705,16 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
// rotations are in absolute rig frame.
|
||||
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(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,
|
||||
// instead of geometry units.
|
||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
||||
data.translationSet = !isEqual(data.translation, defaultRelTrans);
|
||||
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||
} else {
|
||||
data.translationSet = false;
|
||||
data.rotationSet = false;
|
||||
data.translationIsDefaultPose = true;
|
||||
data.rotationIsDefaultPose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1739,11 +1739,11 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
|
||||
for (int i = 0; i < numJoints; 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
|
||||
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);
|
||||
_internalPoseSet._relativePoses[i].scale() = Vectors::ONE;
|
||||
_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
|
||||
_internalPoseSet._relativePoses[i].trans() = _invGeometryOffset.scale() * data.translation;
|
||||
} else {
|
||||
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <AudioHelpers.h>
|
||||
#include <Profile.h>
|
||||
#include <VariantMapToScriptValue.h>
|
||||
#include <BitVectorHelpers.h>
|
||||
|
||||
#include "AvatarLogging.h"
|
||||
|
||||
|
@ -77,6 +78,12 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints) {
|
|||
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() :
|
||||
SpatiallyNestable(NestableType::Avatar, QUuid()),
|
||||
|
@ -272,6 +279,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
bool hasFaceTrackerInfo = false;
|
||||
bool hasJointData = false;
|
||||
bool hasJointDefaultPoseFlags = false;
|
||||
|
||||
if (sendPALMinimum) {
|
||||
hasAudioLoudness = true;
|
||||
|
@ -290,6 +298,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
hasFaceTrackerInfo = !dropFaceTracking && hasFaceTracker() && (sendAll || faceTrackerInfoChangedSince(lastSentTime));
|
||||
hasJointData = sendAll || !sendMinimum;
|
||||
hasJointDefaultPoseFlags = hasJointData;
|
||||
}
|
||||
|
||||
|
||||
|
@ -314,7 +323,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
| (hasParentInfo ? AvatarDataPacket::PACKET_HAS_PARENT_INFO : 0)
|
||||
| (hasAvatarLocalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION : 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));
|
||||
destinationBuffer += sizeof(packetStateFlags);
|
||||
|
@ -541,14 +551,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
for (int i = 0; i < _jointData.size(); i++) {
|
||||
const JointData& data = _jointData[i];
|
||||
const JointData& last = lastSentJointData[i];
|
||||
|
||||
// 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
|
||||
bool largeEnoughRotation = fabsf(glm::dot(data.rotation, lastSentJointData[i].rotation)) < minRotationDOT;
|
||||
if (!data.rotationIsDefaultPose) {
|
||||
if (sendAll || last.rotationIsDefaultPose || last.rotation != data.rotation) {
|
||||
|
||||
if (sendAll || lastSentJointData[i].rotation != data.rotation) {
|
||||
if (sendAll || !cullSmallChanges || largeEnoughRotation) {
|
||||
if (data.rotationSet) {
|
||||
bool largeEnoughRotation = true;
|
||||
if (cullSmallChanges) {
|
||||
// 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);
|
||||
#ifdef WANT_DEBUG
|
||||
rotationSentCount++;
|
||||
|
@ -557,8 +572,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
if (sentJointDataOut) {
|
||||
localSentJointDataOut[i].rotation = data.rotation;
|
||||
localSentJointDataOut[i].rotationIsDefaultPose = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -588,11 +603,10 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
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 ||
|
||||
!cullSmallChanges ||
|
||||
glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
|
||||
if (data.translationSet) {
|
||||
|
||||
if (!data.translationIsDefaultPose) {
|
||||
if (sendAll || lastSentJointData[i].translation != data.translation) {
|
||||
if (sendAll || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
|
||||
validity |= (1 << validityBit);
|
||||
#ifdef WANT_DEBUG
|
||||
translationSentCount++;
|
||||
|
@ -606,8 +620,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
if (sentJointDataOut) {
|
||||
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;
|
||||
|
||||
if (avatarDataSize > (int)byteArraySize) {
|
||||
|
@ -664,6 +702,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.
|
||||
|
@ -674,7 +713,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
|
|||
if (_lastSentJointData[i].rotation != data.rotation) {
|
||||
if (!cullSmallChanges ||
|
||||
fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= AVATAR_MIN_ROTATION_DOT) {
|
||||
if (data.rotationSet) {
|
||||
if (!data.rotationIsDefaultPose) {
|
||||
_lastSentJointData[i].rotation = data.rotation;
|
||||
}
|
||||
}
|
||||
|
@ -682,7 +721,7 @@ void AvatarData::doneEncoding(bool cullSmallChanges) {
|
|||
if (_lastSentJointData[i].translation != data.translation) {
|
||||
if (!cullSmallChanges ||
|
||||
glm::distance(data.translation, _lastSentJointData[i].translation) > AVATAR_MIN_TRANSLATION) {
|
||||
if (data.translationSet) {
|
||||
if (!data.translationIsDefaultPose) {
|
||||
_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
|
||||
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
|
||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||
lazyInitHeadData();
|
||||
|
||||
|
@ -745,18 +785,19 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
|
||||
#define HAS_FLAG(B,F) ((B & F) == F)
|
||||
|
||||
bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION);
|
||||
bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX);
|
||||
bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION);
|
||||
bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE);
|
||||
bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION);
|
||||
bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS);
|
||||
bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX);
|
||||
bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS);
|
||||
bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO);
|
||||
bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION);
|
||||
bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO);
|
||||
bool hasJointData = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_JOINT_DATA);
|
||||
bool hasAvatarGlobalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION);
|
||||
bool hasAvatarBoundingBox = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_BOUNDING_BOX);
|
||||
bool hasAvatarOrientation = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_ORIENTATION);
|
||||
bool hasAvatarScale = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_SCALE);
|
||||
bool hasLookAtPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_LOOK_AT_POSITION);
|
||||
bool hasAudioLoudness = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AUDIO_LOUDNESS);
|
||||
bool hasSensorToWorldMatrix = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_SENSOR_TO_WORLD_MATRIX);
|
||||
bool hasAdditionalFlags = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_ADDITIONAL_FLAGS);
|
||||
bool hasParentInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_PARENT_INFO);
|
||||
bool hasAvatarLocalPosition = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_AVATAR_LOCAL_POSITION);
|
||||
bool hasFaceTrackerInfo = HAS_FLAG(packetStateFlags, AvatarDataPacket::PACKET_HAS_FACE_TRACKER_INFO);
|
||||
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();
|
||||
|
||||
|
@ -1055,7 +1096,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
if (validRotations[i]) {
|
||||
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, data.rotation);
|
||||
_hasNewJointData = true;
|
||||
data.rotationSet = true;
|
||||
data.rotationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1090,7 +1131,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
if (validTranslations[i]) {
|
||||
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||
_hasNewJointData = true;
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1110,6 +1151,32 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
_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;
|
||||
_averageBytesReceived.updateAverage(numBytesRead);
|
||||
|
||||
|
@ -1146,6 +1213,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
|
|||
return _faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "jointData") {
|
||||
return _jointDataRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "jointDefaultPoseFlagsRate") {
|
||||
return _jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "globalPositionOutbound") {
|
||||
return _outboundDataRate.globalPositionRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "localPositionOutbound") {
|
||||
|
@ -1170,6 +1239,8 @@ float AvatarData::getDataRate(const QString& rateName) const {
|
|||
return _outboundDataRate.faceTrackerRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "jointDataOutbound") {
|
||||
return _outboundDataRate.jointDataRate.rate() / BYTES_PER_KILOBIT;
|
||||
} else if (rateName == "jointDefaultPoseFlagsOutbound") {
|
||||
return _outboundDataRate.jointDefaultPoseFlagsRate.rate() / BYTES_PER_KILOBIT;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
@ -1236,9 +1307,9 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v
|
|||
}
|
||||
JointData& data = _jointData[index];
|
||||
data.rotation = rotation;
|
||||
data.rotationSet = true;
|
||||
data.rotationIsDefaultPose = false;
|
||||
data.translation = translation;
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
|
||||
void AvatarData::clearJointData(int index) {
|
||||
|
@ -1294,7 +1365,8 @@ void AvatarData::setJointData(const QString& name, const glm::quat& rotation, co
|
|||
auto& jointData = _jointData[index];
|
||||
jointData.rotation = rotation;
|
||||
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) {
|
||||
auto& data = _jointData[index];
|
||||
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) {
|
||||
auto& data = _jointData[index];
|
||||
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];
|
||||
data.rotation = rotation;
|
||||
data.rotationSet = true;
|
||||
data.rotationIsDefaultPose = false;
|
||||
}
|
||||
|
||||
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];
|
||||
data.translation = translation;
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
|
||||
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) {
|
||||
auto& data = _jointData[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) {
|
||||
auto& data = _jointData[i];
|
||||
data.translation = jointTranslations[i];
|
||||
data.translationSet = true;
|
||||
data.translationIsDefaultPose = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1996,9 +2068,9 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
|
|||
if (json.isArray()) {
|
||||
QJsonArray array = json.toArray();
|
||||
result.rotation = quatFromJsonValue(array[0]);
|
||||
result.rotationSet = true;
|
||||
result.rotationIsDefaultPose = false;
|
||||
result.translation = vec3FromJsonValue(array[1]);
|
||||
result.translationSet = true;
|
||||
result.translationIsDefaultPose = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -113,18 +113,19 @@ namespace AvatarDataPacket {
|
|||
// 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
|
||||
using HasFlags = uint16_t;
|
||||
const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0;
|
||||
const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1;
|
||||
const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2;
|
||||
const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3;
|
||||
const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4;
|
||||
const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5;
|
||||
const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6;
|
||||
const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7;
|
||||
const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8;
|
||||
const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9;
|
||||
const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10;
|
||||
const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11;
|
||||
const HasFlags PACKET_HAS_AVATAR_GLOBAL_POSITION = 1U << 0;
|
||||
const HasFlags PACKET_HAS_AVATAR_BOUNDING_BOX = 1U << 1;
|
||||
const HasFlags PACKET_HAS_AVATAR_ORIENTATION = 1U << 2;
|
||||
const HasFlags PACKET_HAS_AVATAR_SCALE = 1U << 3;
|
||||
const HasFlags PACKET_HAS_LOOK_AT_POSITION = 1U << 4;
|
||||
const HasFlags PACKET_HAS_AUDIO_LOUDNESS = 1U << 5;
|
||||
const HasFlags PACKET_HAS_SENSOR_TO_WORLD_MATRIX = 1U << 6;
|
||||
const HasFlags PACKET_HAS_ADDITIONAL_FLAGS = 1U << 7;
|
||||
const HasFlags PACKET_HAS_PARENT_INFO = 1U << 8;
|
||||
const HasFlags PACKET_HAS_AVATAR_LOCAL_POSITION = 1U << 9;
|
||||
const HasFlags PACKET_HAS_FACE_TRACKER_INFO = 1U << 10;
|
||||
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;
|
||||
|
||||
using SixByteQuat = uint8_t[6];
|
||||
|
@ -256,6 +257,15 @@ namespace AvatarDataPacket {
|
|||
};
|
||||
*/
|
||||
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
|
||||
|
@ -321,6 +331,7 @@ public:
|
|||
RateCounter<> parentInfoRate;
|
||||
RateCounter<> faceTrackerRate;
|
||||
RateCounter<> jointDataRate;
|
||||
RateCounter<> jointDefaultPoseFlagsRate;
|
||||
};
|
||||
|
||||
class AvatarPriority {
|
||||
|
@ -810,6 +821,7 @@ protected:
|
|||
RateCounter<> _parentInfoRate;
|
||||
RateCounter<> _faceTrackerRate;
|
||||
RateCounter<> _jointDataRate;
|
||||
RateCounter<> _jointDefaultPoseFlagsRate;
|
||||
|
||||
// Some rate data for incoming data updates
|
||||
RateCounter<> _parseBufferUpdateRate;
|
||||
|
@ -825,6 +837,7 @@ protected:
|
|||
RateCounter<> _parentInfoUpdateRate;
|
||||
RateCounter<> _faceTrackerUpdateRate;
|
||||
RateCounter<> _jointDataUpdateRate;
|
||||
RateCounter<> _jointDefaultPoseFlagsUpdateRate;
|
||||
|
||||
// Some rate data for outgoing data
|
||||
AvatarDataRate _outboundDataRate;
|
||||
|
|
|
@ -1050,7 +1050,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
return;
|
||||
}
|
||||
|
||||
QVector<JointData> jointsData;
|
||||
QVector<EntityJointData> jointsData;
|
||||
|
||||
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
int frameCount = frames.size();
|
||||
|
|
|
@ -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());
|
||||
_jointDataLock.withWriteLock([&] {
|
||||
for (auto index = 0; index < jointsData.size(); ++index) {
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
virtual void setJointTranslations(const QVector<glm::vec3>& translations);
|
||||
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<bool> getJointRotationsSet() const;
|
||||
|
@ -150,7 +150,7 @@ protected:
|
|||
bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations
|
||||
|
||||
struct ModelJointData {
|
||||
JointData joint;
|
||||
EntityJointData joint;
|
||||
bool rotationDirty { false };
|
||||
bool translationDirty { false };
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::UpdatedMannequinDefaultAvatar);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarJointDefaultPoseFlags);
|
||||
case PacketType::MessagesData:
|
||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||
case PacketType::ICEServerHeartbeat:
|
||||
|
|
|
@ -247,7 +247,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
AvatarIdentitySequenceFront,
|
||||
IsReplicatedInAvatarIdentity,
|
||||
AvatarIdentityLookAtSnapping,
|
||||
UpdatedMannequinDefaultAvatar
|
||||
UpdatedMannequinDefaultAvatar,
|
||||
AvatarJointDefaultPoseFlags
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
58
libraries/shared/src/BitVectorHelpers.h
Normal file
58
libraries/shared/src/BitVectorHelpers.h
Normal 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
|
|
@ -5,14 +5,27 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// Used by the avatar mixer to describe a single joint
|
||||
// These are relative to their parent and translations are in meters
|
||||
class JointData {
|
||||
class EntityJointData {
|
||||
public:
|
||||
glm::quat rotation;
|
||||
glm::vec3 translation;
|
||||
bool rotationSet = false;
|
||||
glm::vec3 translation; // meters
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue