From 7e4c72445ee443886831df517de1942937c3f457 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 20 Aug 2014 17:14:59 -0700 Subject: [PATCH] JS scripts set joint animation priorities --- interface/src/Application.cpp | 8 +++++++ interface/src/avatar/FaceModel.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 31 ++++++++++++++------------ interface/src/avatar/MyAvatar.h | 2 ++ interface/src/avatar/SkeletonModel.cpp | 7 +++--- interface/src/renderer/JointState.cpp | 20 ++++++++++++----- interface/src/renderer/JointState.h | 5 ++++- interface/src/renderer/Model.cpp | 13 ++++------- 8 files changed, 56 insertions(+), 34 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 11729eef90..8421ee05b1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3821,6 +3821,10 @@ void Application::stopAllScripts(bool restart) { it.value()->stop(); qDebug() << "stopping script..." << it.key(); } + // HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities + // whenever a script stops in case it happened to have been setting joint rotations. + // TODO: expose animation priorities and provide a layered animation control system. + _myAvatar->clearJointAnimationPriorities(); } void Application::stopScript(const QString &scriptName) { @@ -3828,6 +3832,10 @@ void Application::stopScript(const QString &scriptName) { if (_scriptEnginesHash.contains(scriptURLString)) { _scriptEnginesHash.value(scriptURLString)->stop(); qDebug() << "stopping script..." << scriptName; + // HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities + // whenever a script stops in case it happened to have been setting joint rotations. + // TODO: expose animation priorities and provide a layered animation control system. + _myAvatar->clearJointAnimationPriorities(); } } diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 203dbf2283..521a4ddc57 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -54,7 +54,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX state.setRotationInConstrainedFrame(glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0])) - * joint.rotation); + * joint.rotation, DEFAULT_PRIORITY); } void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { @@ -69,7 +69,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ glm::quat between = rotationBetween(front, lookAt); const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; state.setRotationInConstrainedFrame(glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - joint.rotation); + joint.rotation, DEFAULT_PRIORITY); } void FaceModel::updateJointState(int index) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b3805d15c7..357a39e17e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -992,36 +992,39 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const { return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f); } -const float JOINT_PRIORITY = 2.0f; +const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; +const float RECORDER_PRIORITY = SCRIPT_PRIORITY + 1.0f; void MyAvatar::setJointRotations(QVector jointRotations) { - for (int i = 0; i < jointRotations.size(); ++i) { - if (i < _jointData.size()) { - _skeletonModel.setJointState(i, true, jointRotations[i], JOINT_PRIORITY + 1.0f); - } + int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size()); + for (int i = 0; i < numStates; ++i) { + // HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here + _skeletonModel.setJointState(i, true, jointRotations[i], RECORDER_PRIORITY); } } void MyAvatar::setJointData(int index, const glm::quat& rotation) { - Avatar::setJointData(index, rotation); if (QThread::currentThread() == thread()) { - _skeletonModel.setJointState(index, true, rotation, JOINT_PRIORITY); + // HACK: ATM only JS scripts call setJointData() on MyAvatar so we hardcode the priority + _skeletonModel.setJointState(index, true, rotation, SCRIPT_PRIORITY); } } void MyAvatar::clearJointData(int index) { - Avatar::clearJointData(index); if (QThread::currentThread() == thread()) { - _skeletonModel.setJointState(index, false, glm::quat(), JOINT_PRIORITY); + // HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority + _skeletonModel.setJointState(index, false, glm::quat(), 0.0f); } } void MyAvatar::clearJointsData() { - for (int i = 0; i < _jointData.size(); ++i) { - Avatar::clearJointData(i); - if (QThread::currentThread() == thread()) { - _skeletonModel.clearJointAnimationPriority(i); - } + clearJointAnimationPriorities(); +} + +void MyAvatar::clearJointAnimationPriorities() { + int numStates = _skeletonModel.getJointStateCount(); + for (int i = 0; i < numStates; ++i) { + _skeletonModel.clearJointAnimationPriority(i); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 42deafd0fa..61708b9e79 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -128,6 +128,8 @@ public: virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); + void clearJointAnimationPriorities(); + virtual void attach(const QString& modelURL, const QString& jointName = QString(), const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, bool allowDuplicates = false, bool useSaved = true); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index a087693615..5a8eb5519d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -51,7 +51,8 @@ void SkeletonModel::setJointStates(QVector states) { } } -const float PALM_PRIORITY = 3.0f; +const float PALM_PRIORITY = DEFAULT_PRIORITY; +const float LEAN_PRIORITY = DEFAULT_PRIORITY; void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getPosition()); @@ -230,7 +231,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { JointState& parentState = _jointStates[parentJointIndex]; parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY); // lock hand to forearm by slamming its rotation (in parent-frame) to identity - _jointStates[jointIndex].setRotationInConstrainedFrame(glm::quat()); + _jointStates[jointIndex].setRotationInConstrainedFrame(glm::quat(), PALM_PRIORITY); } else { inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); } @@ -271,7 +272,7 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, Joint state.setRotationInConstrainedFrame( glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), inverse * zAxis) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), inverse * xAxis) - * state.getFBXJoint().rotation); + * state.getFBXJoint().rotation, LEAN_PRIORITY); } void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index 9492413f54..0776891109 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -145,7 +145,7 @@ glm::quat JointState::getVisibleRotationInParentFrame() const { void JointState::restoreRotation(float fraction, float priority) { assert(_fbxJoint != NULL); if (priority == _animationPriority || _animationPriority == 0.0f) { - setRotationInConstrainedFrame(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction)); + setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction)); _animationPriority = 0.0f; } } @@ -158,7 +158,7 @@ void JointState::setRotationInBindFrame(const glm::quat& rotation, float priorit if (constrain && _constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); } - setRotationInConstrainedFrame(targetRotation); + setRotationInConstrainedFrameInternal(targetRotation); _animationPriority = priority; } } @@ -189,7 +189,7 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa _rotation = delta * getRotation(); return; } - setRotationInConstrainedFrame(targetRotation); + setRotationInConstrainedFrameInternal(targetRotation); } /// Applies delta rotation to joint but mixes a little bit of the default pose as well. @@ -208,7 +208,7 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float if (_constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); } - setRotationInConstrainedFrame(targetRotation); + setRotationInConstrainedFrameInternal(targetRotation); } void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor) { @@ -232,7 +232,17 @@ glm::quat JointState::computeVisibleParentRotation() const { return _visibleRotation * glm::inverse(_fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation); } -void JointState::setRotationInConstrainedFrame(const glm::quat& targetRotation) { +void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain) { + if (priority >= _animationPriority || _animationPriority == 0.0f) { + if (constrain && _constraint) { + _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); + } + setRotationInConstrainedFrameInternal(targetRotation); + _animationPriority = priority; + } +} + +void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) { glm::quat parentRotation = computeParentRotation(); _rotationInConstrainedFrame = targetRotation; _transformChanged = true; diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index bc0c6dd51f..a2c5ee7801 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -19,6 +19,8 @@ #include #include +const float DEFAULT_PRIORITY = 3.0f; + class AngularConstraint; class JointState { @@ -81,7 +83,7 @@ public: /// NOTE: the JointState's model-frame transform/rotation are NOT updated! void setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain = false); - void setRotationInConstrainedFrame(const glm::quat& targetRotation); + void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain = false); void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation); const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; } const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; } @@ -104,6 +106,7 @@ public: glm::quat computeVisibleParentRotation() const; private: + void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation); /// debug helper function void loadBindRotation(); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c955b902c9..92c19dd839 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -438,7 +438,7 @@ void Model::reset() { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); for (int i = 0; i < _jointStates.size(); i++) { - _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation); + _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f); } } @@ -695,8 +695,7 @@ bool Model::getVisibleJointState(int index, glm::quat& rotation) const { void Model::clearJointState(int index) { if (index != -1 && index < _jointStates.size()) { JointState& state = _jointStates[index]; - state.setRotationInConstrainedFrame(glm::quat()); - state._animationPriority = 0.0f; + state.setRotationInConstrainedFrame(glm::quat(), 0.0f); } } @@ -711,8 +710,7 @@ void Model::setJointState(int index, bool valid, const glm::quat& rotation, floa JointState& state = _jointStates[index]; if (priority >= state._animationPriority) { if (valid) { - state.setRotationInConstrainedFrame(rotation); - state._animationPriority = priority; + state.setRotationInConstrainedFrame(rotation, priority); } else { state.restoreRotation(1.0f, priority); } @@ -1745,10 +1743,7 @@ void AnimationHandle::applyFrame(float frameIndex) { int mapping = _jointMappings.at(i); if (mapping != -1) { JointState& state = _model->_jointStates[mapping]; - if (_priority >= state._animationPriority) { - state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction)); - state._animationPriority = _priority; - } + state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), _priority); } } }