diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c8d1747505..b2a3ecbedb 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -714,14 +714,14 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const { void MyAvatar::setJointData(int index, const glm::quat& rotation) { Avatar::setJointData(index, rotation); if (QThread::currentThread() == thread()) { - _skeletonModel.setJointState(index, true, rotation); + _skeletonModel.setJointState(index, true, rotation, 2.0f); } } void MyAvatar::clearJointData(int index) { Avatar::clearJointData(index); if (QThread::currentThread() == thread()) { - _skeletonModel.setJointState(index, false); + _skeletonModel.setJointState(index, false, glm::quat(), 2.0f); } } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 09871ad38b..429ab1cf30 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -21,6 +21,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : _owningAvatar(owningAvatar) { } +const float PALM_PRIORITY = 3.0f; + void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); @@ -43,7 +45,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { } int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex); if (jointIndex != -1) { - setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true); + setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true, PALM_PRIORITY); } } return; @@ -58,16 +60,16 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { if (leftPalmIndex == -1) { // palms are not yet set, use mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { - restoreRightHandPosition(HAND_RESTORATION_RATE); + restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); } - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); @@ -132,7 +134,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) if (jointIndex == -1) { return; } - setJointPosition(jointIndex, position); + setJointPosition(jointIndex, position, glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::vec3 handPosition, elbowPosition; @@ -148,7 +150,8 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector)); + applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), + forearmVector), true, PALM_PRIORITY); } void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { @@ -183,12 +186,14 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); - setJointRotation(parentJointIndex, palmRotation, true); + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), + glm::quat(), false, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); + setJointRotation(parentJointIndex, palmRotation, true, PALM_PRIORITY); _jointStates[jointIndex].rotation = glm::quat(); } else { - setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); + setJointPosition(jointIndex, palm.getPosition(), palmRotation, + true, -1, false, glm::vec3(0.0f, -1.0f, 0.0f), PALM_PRIORITY); } } @@ -335,11 +340,11 @@ void SkeletonModel::setHandPosition(int jointIndex, const glm::vec3& position, c glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f); glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); - setJointRotation(shoulderJointIndex, shoulderRotation, true); + setJointRotation(shoulderJointIndex, shoulderRotation, true, PALM_PRIORITY); setJointRotation(elbowJointIndex, rotationBetween(shoulderRotation * forwardVector, - wristPosition - elbowPosition) * shoulderRotation, true); + wristPosition - elbowPosition) * shoulderRotation, true, PALM_PRIORITY); - setJointRotation(jointIndex, rotation, true); + setJointRotation(jointIndex, rotation, true, PALM_PRIORITY); } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5d0f571b5b..db7e0a7c6d 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -118,7 +118,7 @@ QVector Model::createJointStates(const FBXGeometry& geometry) JointState state; state.translation = joint.translation; state.rotation = joint.rotation; - state.animationDisabled = false; + state.animationPriority = 0.0f; jointStates.append(state); } @@ -473,9 +473,18 @@ bool Model::getJointState(int index, glm::quat& rotation) const { glm::abs(rotation.w - defaultRotation.w) >= EPSILON; } -void Model::setJointState(int index, bool valid, const glm::quat& rotation) { +void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) { if (index != -1 && index < _jointStates.size()) { - _jointStates[index].rotation = valid ? rotation : _geometry->getFBXGeometry().joints.at(index).rotation; + JointState& state = _jointStates[index]; + if (priority >= state.animationPriority) { + if (valid) { + state.rotation = rotation; + state.animationPriority = priority; + } else if (priority == state.animationPriority) { + state.rotation = _geometry->getFBXGeometry().joints.at(index).rotation; + state.animationPriority = 0.0f; + } + } } } @@ -535,8 +544,8 @@ bool Model::getRightHandRotation(glm::quat& rotation) const { return getJointRotation(getRightHandJointIndex(), rotation); } -bool Model::restoreLeftHandPosition(float percent) { - return restoreJointPosition(getLeftHandJointIndex(), percent); +bool Model::restoreLeftHandPosition(float percent, float priority) { + return restoreJointPosition(getLeftHandJointIndex(), percent, priority); } bool Model::getLeftShoulderPosition(glm::vec3& position) const { @@ -547,8 +556,8 @@ float Model::getLeftArmLength() const { return getLimbLength(getLeftHandJointIndex()); } -bool Model::restoreRightHandPosition(float percent) { - return restoreJointPosition(getRightHandJointIndex(), percent); +bool Model::restoreRightHandPosition(float percent, float priority) { + return restoreJointPosition(getRightHandJointIndex(), percent, priority); } bool Model::getRightShoulderPosition(glm::vec3& position) const { @@ -1115,7 +1124,7 @@ void Model::maybeUpdateEyeRotation(const JointState& parentState, const FBXJoint } bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation, - int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment) { + int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } @@ -1138,7 +1147,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat endRotation; if (useRotation) { getJointRotation(jointIndex, endRotation, true); - applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); + applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation), priority); getJointRotation(jointIndex, endRotation, true); } @@ -1182,7 +1191,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const 1.0f / (combinedWeight + 1.0f)); } } - applyRotationDelta(index, combinedDelta); + applyRotationDelta(index, combinedDelta, priority); glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); endPosition = actualDelta * jointVector + jointPosition; if (useRotation) { @@ -1200,15 +1209,17 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const return true; } -bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind) { +bool Model::setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } JointState& state = _jointStates[jointIndex]; - state.rotation = state.rotation * glm::inverse(state.combinedRotation) * rotation * - glm::inverse(fromBind ? _geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation : - _geometry->getFBXGeometry().joints.at(jointIndex).inverseDefaultRotation); - state.animationDisabled = true; + if (priority >= state.animationPriority) { + state.rotation = state.rotation * glm::inverse(state.combinedRotation) * rotation * + glm::inverse(fromBind ? _geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation : + _geometry->getFBXGeometry().joints.at(jointIndex).inverseDefaultRotation); + state.animationPriority = priority; + } return true; } @@ -1229,7 +1240,7 @@ void Model::setJointTranslation(int jointIndex, const glm::vec3& translation) { state.translation = glm::vec3(glm::inverse(parentTransform) * glm::vec4(translation, 1.0f)) - preTranslation; } -bool Model::restoreJointPosition(int jointIndex, float percent) { +bool Model::restoreJointPosition(int jointIndex, float percent, float priority) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } @@ -1238,10 +1249,12 @@ bool Model::restoreJointPosition(int jointIndex, float percent) { foreach (int index, freeLineage) { JointState& state = _jointStates[index]; - const FBXJoint& joint = geometry.joints.at(index); - state.rotation = safeMix(state.rotation, joint.rotation, percent); - state.translation = glm::mix(state.translation, joint.translation, percent); - state.animationDisabled = false; + if (priority == state.animationPriority) { + const FBXJoint& joint = geometry.joints.at(index); + state.rotation = safeMix(state.rotation, joint.rotation, percent); + state.translation = glm::mix(state.translation, joint.translation, percent); + state.animationPriority = 0.0f; + } } return true; } @@ -1260,8 +1273,12 @@ float Model::getLimbLength(int jointIndex) const { return length; } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, float priority) { JointState& state = _jointStates[jointIndex]; + if (priority < state.animationPriority) { + return; + } + state.animationPriority = priority; const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && joint.rotationMax == glm::vec3(PI, PI, PI))) { @@ -1275,7 +1292,6 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; - state.animationDisabled = true; } const int BALL_SUBDIVISIONS = 10; @@ -1749,8 +1765,9 @@ void AnimationHandle::simulate(float deltaTime) { int mapping = _jointMappings.at(i); if (mapping != -1) { Model::JointState& state = _model->_jointStates[mapping]; - if (!state.animationDisabled) { + if (_priority >= state.animationPriority) { state.rotation = frame.rotations.at(i); + state.animationPriority = _priority; } } } @@ -1772,8 +1789,9 @@ void AnimationHandle::simulate(float deltaTime) { int mapping = _jointMappings.at(i); if (mapping != -1) { Model::JointState& state = _model->_jointStates[mapping]; - if (!state.animationDisabled) { + if (_priority >= state.animationPriority) { state.rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction); + state.animationPriority = _priority; } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 979dc6c601..23bde4846b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -113,7 +113,7 @@ public: bool getJointState(int index, glm::quat& rotation) const; /// Sets the joint state at the specified index. - void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat()); + void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); /// Returns the index of the left hand joint, or -1 if not found. int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } @@ -166,7 +166,7 @@ public: /// Restores some percentage of the default position of the left hand. /// \param percent the percentage of the default position to restore /// \return whether or not the left hand joint was found - bool restoreLeftHandPosition(float percent = 1.0f); + bool restoreLeftHandPosition(float percent = 1.0f, float priority = 1.0f); /// Gets the position of the left shoulder. /// \return whether or not the left shoulder joint was found @@ -178,7 +178,7 @@ public: /// Restores some percentage of the default position of the right hand. /// \param percent the percentage of the default position to restore /// \return whether or not the right hand joint was found - bool restoreRightHandPosition(float percent = 1.0f); + bool restoreRightHandPosition(float percent = 1.0f, float priority = 1.0f); /// Gets the position of the right shoulder. /// \return whether or not the right shoulder joint was found @@ -254,7 +254,7 @@ protected: glm::quat rotation; // rotation relative to parent glm::mat4 transform; // rotation to world frame + translation in model frame glm::quat combinedRotation; // rotation from joint local to world frame - bool animationDisabled; // if true, animations do not affect this joint + float animationPriority; // the priority of the animation affecting this joint }; bool _shapesAreDirty; @@ -290,8 +290,8 @@ protected: bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, - const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); - bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false); + const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f), float priority = 1.0f); + bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false, float priority = 1.0f); void setJointTranslation(int jointIndex, const glm::vec3& translation); @@ -299,13 +299,13 @@ protected: /// \param percent the percentage of the default position to apply (i.e., 0.25f to slerp one fourth of the way to /// the original position /// \return true if the joint was found - bool restoreJointPosition(int jointIndex, float percent = 1.0f); + bool restoreJointPosition(int jointIndex, float percent = 1.0f, float priority = 0.0f); /// Computes and returns the extended length of the limb terminating at the specified joint and starting at the joint's /// first free ancestor. float getLimbLength(int jointIndex) const; - void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true); + void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true, float priority = 1.0f); void computeBoundingShape(const FBXGeometry& geometry); diff --git a/interface/src/ui/AnimationsDialog.cpp b/interface/src/ui/AnimationsDialog.cpp index f30c98cce7..205a215b10 100644 --- a/interface/src/ui/AnimationsDialog.cpp +++ b/interface/src/ui/AnimationsDialog.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include #include @@ -80,6 +81,9 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); setLayout(layout); + layout->addRow("Role:", _role = new QComboBox()); + _role->setEditable(true); + QHBoxLayout* urlBox = new QHBoxLayout(); layout->addRow("URL:", urlBox); urlBox->addWidget(_url = new QLineEdit(handle->getURL().toString()), 1); diff --git a/interface/src/ui/AnimationsDialog.h b/interface/src/ui/AnimationsDialog.h index 8b0f6cd257..edda665d10 100644 --- a/interface/src/ui/AnimationsDialog.h +++ b/interface/src/ui/AnimationsDialog.h @@ -18,6 +18,7 @@ #include "avatar/MyAvatar.h" class QCheckBox; +class QComboBox; class QDoubleSpinner; class QLineEdit; class QPushButton; @@ -63,6 +64,7 @@ private: AnimationsDialog* _dialog; AnimationHandlePointer _handle; + QComboBox* _role; QLineEdit* _url; QDoubleSpinBox* _fps; QDoubleSpinBox* _priority;