From 20cac4cd4d92ff5fd59f5826308a91db2f8deb78 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 22 Apr 2019 11:38:27 -0700 Subject: [PATCH] Rotation fix and refactor --- .../src/avatars/AvatarMixerClientData.cpp | 7 --- interface/src/Menu.cpp | 2 + interface/src/Menu.h | 1 + interface/src/avatar/AvatarManager.cpp | 7 +++ interface/src/avatar/AvatarManager.h | 10 ++++ interface/src/avatar/OtherAvatar.cpp | 57 +++++++++++++++++++ interface/src/avatar/OtherAvatar.h | 2 +- .../src/avatars-renderer/Avatar.cpp | 20 +++++-- libraries/avatars/src/AvatarData.cpp | 37 ++++++++---- libraries/avatars/src/AvatarData.h | 14 ++++- libraries/avatars/src/ClientTraitsHandler.cpp | 3 +- 11 files changed, 131 insertions(+), 29 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 29c0697249..3555669c65 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -179,13 +179,6 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, if (packetTraitVersion > _lastReceivedTraitVersions[traitType]) { _avatar->processTrait(traitType, message.read(traitSize)); _lastReceivedTraitVersions[traitType] = packetTraitVersion; - if (traitType == AvatarTraits::SkeletonData) { - qDebug() << "Sending skeleton avatar trait"; - auto packet = NLPacket::create(PacketType::SetAvatarTraits, -1, true); - AvatarTraits::packVersionedTrait(AvatarTraits::SkeletonData, *packet, packetTraitVersion, *_avatar); - auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(packet), sendingNode); - } if (traitType == AvatarTraits::SkeletonModelURL) { // special handling for skeleton model URL, since we need to make sure it is in the whitelist checkSkeletonURLAgainstWhitelist(slaveSharedData, sendingNode, packetTraitVersion); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e9aadea2b6..98c9fd92c9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -627,6 +627,8 @@ Menu::Menu() { avatar.get(), SLOT(setEnableDebugDrawAnimPose(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawPosition, 0, false, avatar.get(), SLOT(setEnableDebugDrawPosition(bool))); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawOtherSkeletons, 0, false, + avatarManager.data(), SLOT(setEnableDebugDrawOtherSkeletons(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true, avatar.get(), SLOT(setEnableMeshVisible(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3611faaf8f..076f54ca1d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -33,6 +33,7 @@ namespace MenuOption { const QString AnimDebugDrawBaseOfSupport = "Debug Draw Base of Support"; const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; + const QString AnimDebugDrawOtherSkeletons = "Debug Draw Other Skeletons"; const QString AskToResetSettings = "Ask To Reset Settings on Start"; const QString AssetMigration = "ATP Asset Migration"; const QString AssetServer = "Asset Browser"; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 575d87dfb7..38dc668ac2 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -120,6 +120,8 @@ void AvatarManager::init() { _myAvatar->addToScene(_myAvatar, scene, transaction); scene->enqueueTransaction(transaction); } + + setEnableDebugDrawOtherSkeletons(Menu::getInstance()->isOptionChecked(MenuOption::AnimDebugDrawOtherSkeletons)); } void AvatarManager::setSpace(workload::SpacePointer& space ) { @@ -334,9 +336,14 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { if (avatar->getSkeletonModel()->isLoaded() && avatar->getWorkloadRegion() == workload::Region::R1) { _myAvatar->addAvatarHandsToFlow(avatar); } + if (_drawOtherAvatarSkeletons) { + avatar->debugJointData(); + } + avatar->setEnableMeshVisible(!_drawOtherAvatarSkeletons); avatar->updateRenderItem(renderTransaction); avatar->updateSpaceProxy(workloadTransaction); avatar->setLastRenderUpdateTime(startTime); + } else { // we've spent our time budget for this priority bucket // let's deal with the reminding avatars if this pass and BREAK from the for loop diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index f9b82da0c1..bbc27b3d47 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -213,6 +213,15 @@ public slots: */ void updateAvatarRenderStatus(bool shouldRenderAvatars); + /**jsdoc + * Displays other avatars skeletons debug graphics. + * @function AvatarManager.setEnableDebugDrawOtherSkeletons + * @param {boolean} enabled - true to show the debug graphics, false to hide. + */ + void setEnableDebugDrawOtherSkeletons(bool isEnabled) { + _drawOtherAvatarSkeletons = isEnabled; + } + protected: AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; @@ -250,6 +259,7 @@ private: workload::SpacePointer _space; AvatarTransit::TransitConfig _transitConfig; + bool _drawOtherAvatarSkeletons { false }; }; #endif // hifi_AvatarManager_h diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index 2e775a20c3..f179f4498e 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -16,6 +16,7 @@ #include "Application.h" #include "AvatarMotionState.h" #include "DetailedMotionState.h" +#include "DebugDraw.h" const float DISPLAYNAME_FADE_TIME = 0.5f; const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME); @@ -358,6 +359,62 @@ void OtherAvatar::simulate(float deltaTime, bool inView) { } } +void OtherAvatar::debugJointData() const { + // Get a copy of the joint data + auto jointData = getJointData(); + auto skeletonData = getSkeletonData(); + if ((int)skeletonData.size() == jointData.size() && jointData.size() != 0) { + const vec4 RED(1.0f, 0.0f, 0.0f, 1.0f); + const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f); + const vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f); + const vec4 LIGHT_RED(1.0f, 0.5f, 0.5f, 1.0f); + const vec4 LIGHT_GREEN(0.5f, 1.0f, 0.5f, 1.0f); + const vec4 LIGHT_BLUE(0.5f, 0.5f, 1.0f, 1.0f); + const vec4 GREY(0.3f, 0.3f, 0.3f, 1.0f); + const vec4 WHITE(1.0f, 1.0f, 1.0f, 1.0f); + const float AXIS_LENGTH = 0.1f; + + std::vector jointPoses; + glm::quat rotationOffset = Quaternions::IDENTITY; + std::vector jointNames; + AnimPose rigToAvatar = AnimPose(Quaternions::Y_180 * getWorldOrientation(), getWorldPosition()); + for (int i = 0; i < jointData.size(); i++) { + float jointScale = skeletonData[i].defaultScale * getTargetScale(); + auto jointRotation = rigToAvatar.rot() * (jointData[i].rotationIsDefaultPose ? skeletonData[i].defaultRotation : jointData[i].rotation); + auto jointTranslation = jointScale * (jointData[i].translationIsDefaultPose ? skeletonData[i].defaultTranslation : jointData[i].translation); + if (skeletonData[i].jointName == "Hips") { + jointTranslation = glm::vec3(0.0f); + } + jointPoses.push_back(AnimPose(jointRotation, jointTranslation)); + jointNames.push_back(skeletonData[i].jointName); + } + QVector worldFramePoses; + for (size_t i = 0; i < jointPoses.size(); i++) { + auto &jointPose = jointPoses[i]; + int parentIndex = skeletonData[i].parentIndex; + if (parentIndex < worldFramePoses.size()) { + glm::vec3 xAxis = jointPose.rot() * Vectors::UNIT_X; + glm::vec3 yAxis = jointPose.rot() * Vectors::UNIT_Y; + glm::vec3 zAxis = jointPose.rot() * Vectors::UNIT_Z; + + auto parentRotation = parentIndex > -1 ? jointPoses[parentIndex].rot() : Quaternions::IDENTITY; + auto parentPosition = parentIndex > -1 ? worldFramePoses[parentIndex].trans() : rigToAvatar.trans(); + auto jointPosition = parentPosition + parentRotation * (jointPose.trans() * METERS_PER_CENTIMETER); + worldFramePoses.push_back(AnimPose(jointPose.rot(), jointPosition)); + + DebugDraw::getInstance().drawRay(jointPosition, jointPosition + AXIS_LENGTH * xAxis, jointData[i].rotationIsDefaultPose ? LIGHT_RED : RED); + DebugDraw::getInstance().drawRay(jointPosition, jointPosition + AXIS_LENGTH * yAxis, jointData[i].rotationIsDefaultPose ? LIGHT_GREEN : GREEN); + DebugDraw::getInstance().drawRay(jointPosition, jointPosition + AXIS_LENGTH * zAxis, jointData[i].rotationIsDefaultPose ? LIGHT_BLUE : BLUE); + // draw line to parent + if (parentIndex != -1) { + DebugDraw::getInstance().drawRay(jointPosition, parentPosition, jointData[i].translationIsDefaultPose ? WHITE : GREY); + } + } + } + + } +} + void OtherAvatar::handleChangedAvatarEntityData() { PerformanceTimer perfTimer("attachments"); diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index 7669f44806..743356f71d 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -66,7 +66,7 @@ public: void setCollisionWithOtherAvatarsFlags() override; void simulate(float deltaTime, bool inView) override; - + void OtherAvatar::debugJointData() const; friend AvatarManager; protected: diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 0d78bd810a..1129bee7e9 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1452,15 +1452,25 @@ QStringList Avatar::getJointNames() const { std::vector Avatar::getSkeletonDefaultData() { std::vector defaultSkeletonData; if (_skeletonModel->isLoaded()) { - auto jointNames = getJointNames(); + auto &model = _skeletonModel->getHFMModel(); + auto &rig = _skeletonModel->getRig(); + float geometryToRigScale = glm::length(extractScale(rig.getGeometryToRigTransform())); + QStringList jointNames = getJointNames(); int sizeCount = 0; - for (int i = 0; i < min(43, jointNames.size()); i++) { + int jointCount = 0; + for (int i = 0; i < jointNames.size(); i++) { AvatarSkeletonTrait::UnpackedJointData jointData; - jointData.jointParent = _skeletonModel->getRig().getJointParentIndex(i); jointData.jointIndex = i; - jointData.defaultRotation = getDefaultJointRotation(i); + jointData.parentIndex = rig.getJointParentIndex(i); + if (jointData.parentIndex == -1) { + jointData.boneType = model.joints[i].isSkeletonJoint ? AvatarSkeletonTrait::BoneType::SkeletonRoot : AvatarSkeletonTrait::BoneType::NonSkeletonRoot; + } else { + jointData.boneType = model.joints[i].isSkeletonJoint ? AvatarSkeletonTrait::BoneType::SkeletonChild : AvatarSkeletonTrait::BoneType::NonSkeletonChild; + } + jointData.defaultRotation = rig.getAbsoluteDefaultPose(i).rot(); jointData.defaultTranslation = getDefaultJointTranslation(i); - jointData.defaultScale = glm::length(getAbsoluteJointScaleInObjectFrame(i)); + float jointLocalScale = glm::length(extractScale(model.joints[i].transform)); + jointData.defaultScale = jointLocalScale / geometryToRigScale; jointData.jointName = jointNames[i]; jointData.stringLength = jointNames[i].size(); jointData.stringStart = sizeCount; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3491933ce5..5e68a26512 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1635,6 +1635,13 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v data.translationIsDefaultPose = false; } +QVector AvatarData::getJointData() const { + QVector jointData; + QReadLocker readLock(&_jointDataLock); + jointData = _jointData; + return jointData; +} + void AvatarData::clearJointData(int index) { if (index < 0 || index >= LOWEST_PSEUDO_JOINT_INDEX) { return; @@ -1991,17 +1998,17 @@ QUrl AvatarData::getWireSafeSkeletonModelURL() const { } } QByteArray AvatarData::packSkeletonData() const { + // Send an avatar trait packet with the skeleton data before the mesh is loaded int avatarDataSize = 0; QByteArray avatarDataByteArray; - //_avatarSkeletonDataLock.withReadLock([&] { + _avatarSkeletonDataLock.withReadLock([&] { // Add header AvatarSkeletonTrait::Header header; header.maxScaleDimension = 0.0f; header.maxTranslationDimension = 0.0f; header.numJoints = (uint8_t)_avatarSkeletonData.size(); - header.padding = 0; header.stringTableLength = 0; - qDebug() << "Dealing with: " << _avatarSkeletonData.size() << " joints"; + for (size_t i = 0; i < _avatarSkeletonData.size(); i++) { header.stringTableLength += (uint16_t)_avatarSkeletonData[i].jointName.size(); auto &translation = _avatarSkeletonData[i].defaultTranslation; @@ -2021,7 +2028,7 @@ QByteArray AvatarData::packSkeletonData() const { for (size_t i = 0; i < _avatarSkeletonData.size(); i++) { AvatarSkeletonTrait::JointData jdata; jdata.boneType = _avatarSkeletonData[i].boneType; - jdata.jointParent = _avatarSkeletonData[i].jointParent; + jdata.parentIndex = _avatarSkeletonData[i].parentIndex; packFloatRatioToTwoByte((uint8_t*)(&jdata.defaultScale), _avatarSkeletonData[i].defaultScale / header.maxScaleDimension); packOrientationQuatToSixBytes(jdata.defaultRotation, _avatarSkeletonData[i].defaultRotation); packFloatVec3ToSignedTwoByteFixed(jdata.defaultTranslation, _avatarSkeletonData[i].defaultTranslation / header.maxTranslationDimension, TRANSLATION_COMPRESSION_RADIX); @@ -2037,8 +2044,7 @@ QByteArray AvatarData::packSkeletonData() const { destinationBuffer += header.stringTableLength; avatarDataSize = destinationBuffer - startPosition; - qDebug() << "Data size: " << avatarDataSize; - //}); + }); return avatarDataByteArray.left(avatarDataSize); } @@ -2064,20 +2070,22 @@ void AvatarData::unpackSkeletonData(const QByteArray& data) { uJointData.jointIndex = (int)i; uJointData.stringLength = (int)jointData->stringLength; uJointData.stringStart = (int)jointData->stringStart; + uJointData.parentIndex = ((uJointData.boneType == AvatarSkeletonTrait::BoneType::SkeletonRoot) || + (uJointData.boneType == AvatarSkeletonTrait::BoneType::NonSkeletonRoot)) ? -1 : (int)jointData->parentIndex; unpackOrientationQuatFromSixBytes(reinterpret_cast(&jointData->defaultRotation), uJointData.defaultRotation); unpackFloatVec3FromSignedTwoByteFixed(reinterpret_cast(&jointData->defaultTranslation), uJointData.defaultTranslation, TRANSLATION_COMPRESSION_RADIX); - unpackFloatScalarFromSignedTwoByteFixed((const int16_t*)(&jointData->defaultScale), &uJointData.defaultScale, TRANSLATION_COMPRESSION_RADIX); + unpackFloatRatioFromTwoByte(reinterpret_cast(&jointData->defaultScale), uJointData.defaultScale); uJointData.defaultTranslation *= header->maxTranslationDimension; uJointData.defaultScale *= header->maxScaleDimension; joints.push_back(uJointData); } - qDebug() << "_____length: " << header->stringTableLength; QString table = QString::fromUtf8(reinterpret_cast(sourceBuffer), (int)header->stringTableLength); for (size_t i = 0; i < joints.size(); i++) { QStringRef subString(&table, joints[i].stringStart, joints[i].stringLength); joints[i].jointName = subString.toString(); - qDebug() << "_____data: " << joints[i].boneType << " " << joints[i].jointIndex << " " << joints[i].stringLength << " " << joints[i].stringStart << " " << joints[i].defaultRotation << " " << joints[i].defaultScale << joints[i].defaultTranslation; - qDebug() << "_____JointNameReveived: " << joints[i].jointName; + } + if (_clientTraitsHandler) { + _clientTraitsHandler->markTraitUpdated(AvatarTraits::SkeletonData); } setSkeletonData(joints); } @@ -2204,7 +2212,6 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { } _skeletonModelURL = expanded; - if (_clientTraitsHandler) { _clientTraitsHandler->markTraitUpdated(AvatarTraits::SkeletonModelURL); } @@ -3094,6 +3101,14 @@ void AvatarData::setSkeletonData(const std::vector AvatarData::getSkeletonData() const { + std::vector skeletonData; + _avatarSkeletonDataLock.withReadLock([&] { + skeletonData = _avatarSkeletonData; + }); + return skeletonData; +} + void AvatarData::sendSkeletonData() const{ if (_clientTraitsHandler) { _clientTraitsHandler->markTraitUpdated(AvatarTraits::SkeletonData); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a0ce5b2201..08e5db61e7 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -146,11 +146,17 @@ const char AVATARDATA_FLAGS_MINIMUM = 0; using SmallFloat = uint16_t; // a compressed float with less precision, user defined radix namespace AvatarSkeletonTrait { + enum BoneType { + SkeletonRoot = 0, + SkeletonChild, + NonSkeletonRoot, + NonSkeletonChild + }; + PACKED_BEGIN struct Header { float maxTranslationDimension; float maxScaleDimension; uint8_t numJoints; - uint8_t padding; uint16_t stringTableLength; } PACKED_END; @@ -162,11 +168,10 @@ namespace AvatarSkeletonTrait { uint8_t defaultRotation[6]; uint16_t defaultScale; uint16_t jointIndex; - uint16_t jointParent; + uint16_t parentIndex; } PACKED_END; struct UnpackedJointData { - int jointParent; int stringStart; int stringLength; int boneType; @@ -174,6 +179,7 @@ namespace AvatarSkeletonTrait { glm::quat defaultRotation; float defaultScale; int jointIndex; + int parentIndex; QString jointName; }; } @@ -1454,7 +1460,9 @@ public: bool getIsNewAvatar() { return _isNewAvatar; } void setIsClientAvatar(bool isClientAvatar) { _isClientAvatar = isClientAvatar; } void setSkeletonData(const std::vector& skeletonData); + std::vector getSkeletonData() const; void sendSkeletonData() const; + QVector getJointData() const; signals: diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index f6bd66e89a..8f6871f0e9 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -107,8 +107,7 @@ int ClientTraitsHandler::sendChangedTraitsToMixer() { if (initialSend || *simpleIt == Updated) { bytesWritten += AvatarTraits::packTrait(traitType, *traitsPacketList, *_owningAvatar); - - + if (traitType == AvatarTraits::SkeletonModelURL) { // keep track of our skeleton version in case we get an override back _currentSkeletonVersion = _currentTraitVersion;