From 7da5fa9ea7fcba68b9c4ac46af3d558c5a0b3cba Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 16 Oct 2018 11:33:58 -0700 Subject: [PATCH] Transit animations won't play, they just get sent over the network --- interface/src/avatar/AvatarManager.cpp | 8 +- interface/src/avatar/MyAvatar.cpp | 17 ++++ interface/src/avatar/MyAvatar.h | 2 + libraries/animation/src/Rig.cpp | 120 +++++++++++++++++++++++-- libraries/animation/src/Rig.h | 8 ++ 5 files changed, 146 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c1fddaa680..373ae9980a 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -151,22 +151,22 @@ void AvatarManager::handleTransitAnimations(AvatarTransit::Status status) { switch (status) { case AvatarTransit::Status::STARTED: qDebug() << "START_FRAME"; - _myAvatar->overrideAnimation(startAnimation._animationUrl, REFERENCE_FPS, false, startAnimation._firstFrame, + _myAvatar->overrideNetworkAnimation(startAnimation._animationUrl, REFERENCE_FPS, false, startAnimation._firstFrame, startAnimation._firstFrame + startAnimation._frameCount); break; case AvatarTransit::Status::START_TRANSIT: qDebug() << "START_TRANSIT"; - _myAvatar->overrideAnimation(middleAnimation._animationUrl, REFERENCE_FPS, false, middleAnimation._firstFrame, + _myAvatar->overrideNetworkAnimation(middleAnimation._animationUrl, REFERENCE_FPS, false, middleAnimation._firstFrame, middleAnimation._firstFrame + middleAnimation._frameCount); break; case AvatarTransit::Status::END_TRANSIT: qDebug() << "END_TRANSIT"; - _myAvatar->overrideAnimation(endAnimation._animationUrl, REFERENCE_FPS, false, endAnimation._firstFrame, + _myAvatar->overrideNetworkAnimation(endAnimation._animationUrl, REFERENCE_FPS, false, endAnimation._firstFrame, endAnimation._firstFrame + endAnimation._frameCount); break; case AvatarTransit::Status::ENDED: qDebug() << "END_FRAME"; - _myAvatar->restoreAnimation(); + _myAvatar->restoreNetworkAnimation(); break; case AvatarTransit::Status::PRE_TRANSIT: break; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b347963cf1..152215e717 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1124,6 +1124,15 @@ void MyAvatar::overrideAnimation(const QString& url, float fps, bool loop, float _skeletonModel->getRig().overrideAnimation(url, fps, loop, firstFrame, lastFrame); } +void MyAvatar::overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "overrideNetworkAnimation", Q_ARG(const QString&, url), Q_ARG(float, fps), + Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame)); + return; + } + _skeletonModel->getRig().overrideNetworkAnimation(url, fps, loop, firstFrame, lastFrame); +} + void MyAvatar::restoreAnimation() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "restoreAnimation"); @@ -1132,6 +1141,14 @@ void MyAvatar::restoreAnimation() { _skeletonModel->getRig().restoreAnimation(); } +void MyAvatar::restoreNetworkAnimation() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "restoreNetworkAnimation"); + return; + } + _skeletonModel->getRig().restoreNetworkAnimation(); +} + QStringList MyAvatar::getAnimationRoles() { if (QThread::currentThread() != thread()) { QStringList result; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 16b765711a..9770a5bb1a 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -376,6 +376,7 @@ public: * }, 3000); */ Q_INVOKABLE void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame); + Q_INVOKABLE void overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame); /**jsdoc * The avatar animation system includes a set of default animations along with rules for how those animations are blended together with @@ -392,6 +393,7 @@ public: * }, 3000); */ Q_INVOKABLE void restoreAnimation(); + Q_INVOKABLE void restoreNetworkAnimation(); /**jsdoc * Each avatar has an avatar-animation.json file that defines which animations are used and how they are blended together with procedural data diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 91d4e0f9d3..b9e654964a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -133,6 +133,43 @@ void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firs _animVars.set("userAnimB", clipNodeEnum == UserAnimState::B); } +void Rig::overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) { + UserAnimState::ClipNodeEnum clipNodeEnum; + if (_networkAnimState.clipNodeEnum == UserAnimState::None || _networkAnimState.clipNodeEnum == UserAnimState::B) { + clipNodeEnum = UserAnimState::A; + } + else { + clipNodeEnum = UserAnimState::B; + } + if (_networkNode) { + // find an unused AnimClip clipNode + _sendNetworkNode = true; + std::shared_ptr clip; + if (clipNodeEnum == UserAnimState::A) { + clip = std::dynamic_pointer_cast(_networkNode->findByName("userAnimA")); + } + else { + clip = std::dynamic_pointer_cast(_networkNode->findByName("userAnimB")); + } + if (clip) { + // set parameters + clip->setLoopFlag(loop); + clip->setStartFrame(firstFrame); + clip->setEndFrame(lastFrame); + const float REFERENCE_FRAMES_PER_SECOND = 30.0f; + float timeScale = fps / REFERENCE_FRAMES_PER_SECOND; + clip->setTimeScale(timeScale); + clip->loadURL(url); + } + } + // store current user anim state. + _networkAnimState = { clipNodeEnum, url, fps, loop, firstFrame, lastFrame }; + // notify the userAnimStateMachine the desired state. + _networkVars.set("userAnimNone", false); + _networkVars.set("userAnimA", clipNodeEnum == UserAnimState::A); + _networkVars.set("userAnimB", clipNodeEnum == UserAnimState::B); +} + void Rig::restoreAnimation() { if (_userAnimState.clipNodeEnum != UserAnimState::None) { _userAnimState.clipNodeEnum = UserAnimState::None; @@ -144,6 +181,17 @@ void Rig::restoreAnimation() { } } +void Rig::restoreNetworkAnimation() { + _sendNetworkNode = false; + if (_networkAnimState.clipNodeEnum != UserAnimState::None) { + _networkAnimState.clipNodeEnum = UserAnimState::None; + // notify the userAnimStateMachine the desired state. + _networkVars.set("userAnimNone", true); + _networkVars.set("userAnimA", false); + _networkVars.set("userAnimB", false); + } +} + QStringList Rig::getAnimationRoles() const { if (_animNode) { QStringList list; @@ -208,11 +256,17 @@ void Rig::restoreRoleAnimation(const QString& role) { void Rig::destroyAnimGraph() { _animSkeleton.reset(); _animLoader.reset(); + _networkLoader.reset(); _animNode.reset(); _internalPoseSet._relativePoses.clear(); _internalPoseSet._absolutePoses.clear(); _internalPoseSet._overridePoses.clear(); _internalPoseSet._overrideFlags.clear(); + _networkNode.reset(); + _networkPoseSet._relativePoses.clear(); + _networkPoseSet._absolutePoses.clear(); + _networkPoseSet._overridePoses.clear(); + _networkPoseSet._overrideFlags.clear(); _numOverrides = 0; _leftEyeJointChildren.clear(); _rightEyeJointChildren.clear(); @@ -229,14 +283,24 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff _internalPoseSet._relativePoses.clear(); _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); + _networkPoseSet._relativePoses.clear(); + _networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); _internalPoseSet._overridePoses.clear(); _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); _internalPoseSet._overrideFlags.clear(); _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + + _networkPoseSet._overridePoses.clear(); + _networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); + + _networkPoseSet._overrideFlags.clear(); + _networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _numOverrides = 0; buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -270,6 +334,18 @@ void Rig::reset(const FBXGeometry& geometry) { _internalPoseSet._overrideFlags.clear(); _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + + _networkPoseSet._relativePoses.clear(); + _networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); + + buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); + + _networkPoseSet._overridePoses.clear(); + _networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); + + _networkPoseSet._overrideFlags.clear(); + _networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _numOverrides = 0; buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -1049,26 +1125,37 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons updateAnimationStateHandlers(); _animVars.setRigToGeometryTransform(_rigToGeometryTransform); - + if (_networkNode) { + _networkVars.setRigToGeometryTransform(_rigToGeometryTransform); + } AnimContext context(_enableDebugDrawIKTargets, _enableDebugDrawIKConstraints, _enableDebugDrawIKChains, getGeometryToRigTransform(), rigToWorldTransform); // evaluate the animation AnimVariantMap triggersOut; - + AnimVariantMap networkTriggersOut; _internalPoseSet._relativePoses = _animNode->evaluate(_animVars, context, deltaTime, triggersOut); + if (_networkNode) { + _networkPoseSet._relativePoses = _networkNode->evaluate(_networkVars, context, deltaTime, networkTriggersOut); + } if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) { // animations haven't fully loaded yet. _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); } + if ((int)_networkPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) { + // animations haven't fully loaded yet. + _networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); + } _lastAnimVars = _animVars; _animVars.clearTriggers(); _animVars = triggersOut; + _networkVars.clearTriggers(); + _networkVars = networkTriggersOut; _lastContext = context; } applyOverridePoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - + buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); // copy internal poses to external poses { QWriteLocker writeLock(&_externalPoseSetLock); @@ -1707,9 +1794,12 @@ void Rig::initAnimGraph(const QUrl& url) { _animGraphURL = url; _animNode.reset(); + _networkNode.reset(); // load the anim graph _animLoader.reset(new AnimNodeLoader(url)); + _networkLoader.reset(new AnimNodeLoader(url)); + std::weak_ptr weakSkeletonPtr = _animSkeleton; connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) { _animNode = nodeIn; @@ -1740,6 +1830,26 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { qCCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str; }); + + connect(_networkLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) { + _networkNode = nodeIn; + // abort load if the previous skeleton was deleted. + auto sharedSkeletonPtr = weakSkeletonPtr.lock(); + if (!sharedSkeletonPtr) { + return; + } + _networkNode->setSkeleton(sharedSkeletonPtr); + if (_networkAnimState.clipNodeEnum != UserAnimState::None) { + // restore the user animation we had before reset. + UserAnimState origState = _networkAnimState; + _networkAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f }; + overrideNetworkAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame); + } + // emit onLoadComplete(); + }); + connect(_networkLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { + qCCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str; + }); } } @@ -1817,13 +1927,13 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { if (isIndexValid(i)) { // rotations are in absolute rig frame. glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot(); - data.rotation = _internalPoseSet._absolutePoses[i].rot(); + data.rotation = !_sendNetworkNode ? _internalPoseSet._absolutePoses[i].rot() : _networkPoseSet._absolutePoses[i].rot(); 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.translation = _geometryOffset.scale() * (!_sendNetworkNode ? _internalPoseSet._relativePoses[i].trans() : _networkPoseSet._relativePoses[i].trans()); data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans); } else { data.translationIsDefaultPose = true; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 48f00d4e5d..e1012df029 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -113,7 +113,9 @@ public: void destroyAnimGraph(); void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame); + void overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame); void restoreAnimation(); + void restoreNetworkAnimation(); QStringList getAnimationRoles() const; void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame); void restoreRoleAnimation(const QString& role); @@ -270,6 +272,7 @@ protected: // Only accessed by the main thread PoseSet _internalPoseSet; + PoseSet _networkPoseSet; // Copy of the _poseSet for external threads. PoseSet _externalPoseSet; @@ -301,9 +304,12 @@ protected: QUrl _animGraphURL; std::shared_ptr _animNode; + std::shared_ptr _networkNode; std::shared_ptr _animSkeleton; std::unique_ptr _animLoader; + std::unique_ptr _networkLoader; AnimVariantMap _animVars; + AnimVariantMap _networkVars; enum class RigRole { Idle = 0, @@ -350,6 +356,7 @@ protected: }; UserAnimState _userAnimState; + UserAnimState _networkAnimState; std::map _roleAnimStates; float _leftHandOverlayAlpha { 0.0f }; @@ -391,6 +398,7 @@ protected: int _rigId; bool _headEnabled { false }; + bool _sendNetworkNode { false }; AnimContext _lastContext; AnimVariantMap _lastAnimVars;