Working on handling animation priorities to prevent Hydra move/restore from

interfering with scripted animations.
This commit is contained in:
Andrzej Kapolka 2014-05-22 14:41:46 -07:00
parent 03abad4f20
commit d4af39a9f5
6 changed files with 75 additions and 46 deletions

View file

@ -714,14 +714,14 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const {
void MyAvatar::setJointData(int index, const glm::quat& rotation) { void MyAvatar::setJointData(int index, const glm::quat& rotation) {
Avatar::setJointData(index, rotation); Avatar::setJointData(index, rotation);
if (QThread::currentThread() == thread()) { if (QThread::currentThread() == thread()) {
_skeletonModel.setJointState(index, true, rotation); _skeletonModel.setJointState(index, true, rotation, 2.0f);
} }
} }
void MyAvatar::clearJointData(int index) { void MyAvatar::clearJointData(int index) {
Avatar::clearJointData(index); Avatar::clearJointData(index);
if (QThread::currentThread() == thread()) { if (QThread::currentThread() == thread()) {
_skeletonModel.setJointState(index, false); _skeletonModel.setJointState(index, false, glm::quat(), 2.0f);
} }
} }

View file

@ -21,6 +21,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) :
_owningAvatar(owningAvatar) { _owningAvatar(owningAvatar) {
} }
const float PALM_PRIORITY = 3.0f;
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
setTranslation(_owningAvatar->getPosition()); setTranslation(_owningAvatar->getPosition());
setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); 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); int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex);
if (jointIndex != -1) { if (jointIndex != -1) {
setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true); setJointRotation(jointIndex, _rotation * prioVR->getJointRotations().at(i), true, PALM_PRIORITY);
} }
} }
return; return;
@ -58,16 +60,16 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
if (leftPalmIndex == -1) { if (leftPalmIndex == -1) {
// palms are not yet set, use mouse // palms are not yet set, use mouse
if (_owningAvatar->getHandState() == HAND_STATE_NULL) { if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
restoreRightHandPosition(HAND_RESTORATION_RATE); restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else { } else {
applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition());
} }
restoreLeftHandPosition(HAND_RESTORATION_RATE); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else if (leftPalmIndex == rightPalmIndex) { } else if (leftPalmIndex == rightPalmIndex) {
// right hand only // right hand only
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]);
restoreLeftHandPosition(HAND_RESTORATION_RATE); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else { } else {
applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
@ -132,7 +134,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
if (jointIndex == -1) { if (jointIndex == -1) {
return; 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(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::vec3 handPosition, elbowPosition; glm::vec3 handPosition, elbowPosition;
@ -148,7 +150,8 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
// align hand with forearm // align hand with forearm
float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; 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) { 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)) { } else if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) {
glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f);
setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * setJointPosition(parentJointIndex, palm.getPosition() + forearmVector *
geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale),
setJointRotation(parentJointIndex, palmRotation, true); 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(); _jointStates[jointIndex].rotation = glm::quat();
} else { } 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::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition); glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
setJointRotation(shoulderJointIndex, shoulderRotation, true); setJointRotation(shoulderJointIndex, shoulderRotation, true, PALM_PRIORITY);
setJointRotation(elbowJointIndex, rotationBetween(shoulderRotation * forwardVector, 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);
} }

View file

@ -118,7 +118,7 @@ QVector<Model::JointState> Model::createJointStates(const FBXGeometry& geometry)
JointState state; JointState state;
state.translation = joint.translation; state.translation = joint.translation;
state.rotation = joint.rotation; state.rotation = joint.rotation;
state.animationDisabled = false; state.animationPriority = 0.0f;
jointStates.append(state); jointStates.append(state);
} }
@ -473,9 +473,18 @@ bool Model::getJointState(int index, glm::quat& rotation) const {
glm::abs(rotation.w - defaultRotation.w) >= EPSILON; 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()) { 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); return getJointRotation(getRightHandJointIndex(), rotation);
} }
bool Model::restoreLeftHandPosition(float percent) { bool Model::restoreLeftHandPosition(float percent, float priority) {
return restoreJointPosition(getLeftHandJointIndex(), percent); return restoreJointPosition(getLeftHandJointIndex(), percent, priority);
} }
bool Model::getLeftShoulderPosition(glm::vec3& position) const { bool Model::getLeftShoulderPosition(glm::vec3& position) const {
@ -547,8 +556,8 @@ float Model::getLeftArmLength() const {
return getLimbLength(getLeftHandJointIndex()); return getLimbLength(getLeftHandJointIndex());
} }
bool Model::restoreRightHandPosition(float percent) { bool Model::restoreRightHandPosition(float percent, float priority) {
return restoreJointPosition(getRightHandJointIndex(), percent); return restoreJointPosition(getRightHandJointIndex(), percent, priority);
} }
bool Model::getRightShoulderPosition(glm::vec3& position) const { 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, 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()) { if (jointIndex == -1 || _jointStates.isEmpty()) {
return false; return false;
} }
@ -1138,7 +1147,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
glm::quat endRotation; glm::quat endRotation;
if (useRotation) { if (useRotation) {
getJointRotation(jointIndex, endRotation, true); getJointRotation(jointIndex, endRotation, true);
applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation), priority);
getJointRotation(jointIndex, endRotation, true); getJointRotation(jointIndex, endRotation, true);
} }
@ -1182,7 +1191,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
1.0f / (combinedWeight + 1.0f)); 1.0f / (combinedWeight + 1.0f));
} }
} }
applyRotationDelta(index, combinedDelta); applyRotationDelta(index, combinedDelta, priority);
glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation);
endPosition = actualDelta * jointVector + jointPosition; endPosition = actualDelta * jointVector + jointPosition;
if (useRotation) { if (useRotation) {
@ -1200,15 +1209,17 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const
return true; 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()) { if (jointIndex == -1 || _jointStates.isEmpty()) {
return false; return false;
} }
JointState& state = _jointStates[jointIndex]; JointState& state = _jointStates[jointIndex];
state.rotation = state.rotation * glm::inverse(state.combinedRotation) * rotation * if (priority >= state.animationPriority) {
glm::inverse(fromBind ? _geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation : state.rotation = state.rotation * glm::inverse(state.combinedRotation) * rotation *
_geometry->getFBXGeometry().joints.at(jointIndex).inverseDefaultRotation); glm::inverse(fromBind ? _geometry->getFBXGeometry().joints.at(jointIndex).inverseBindRotation :
state.animationDisabled = true; _geometry->getFBXGeometry().joints.at(jointIndex).inverseDefaultRotation);
state.animationPriority = priority;
}
return true; 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; 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()) { if (jointIndex == -1 || _jointStates.isEmpty()) {
return false; return false;
} }
@ -1238,10 +1249,12 @@ bool Model::restoreJointPosition(int jointIndex, float percent) {
foreach (int index, freeLineage) { foreach (int index, freeLineage) {
JointState& state = _jointStates[index]; JointState& state = _jointStates[index];
const FBXJoint& joint = geometry.joints.at(index); if (priority == state.animationPriority) {
state.rotation = safeMix(state.rotation, joint.rotation, percent); const FBXJoint& joint = geometry.joints.at(index);
state.translation = glm::mix(state.translation, joint.translation, percent); state.rotation = safeMix(state.rotation, joint.rotation, percent);
state.animationDisabled = false; state.translation = glm::mix(state.translation, joint.translation, percent);
state.animationPriority = 0.0f;
}
} }
return true; return true;
} }
@ -1260,8 +1273,12 @@ float Model::getLimbLength(int jointIndex) const {
return length; 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]; JointState& state = _jointStates[jointIndex];
if (priority < state.animationPriority) {
return;
}
state.animationPriority = priority;
const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex];
if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) &&
joint.rotationMax == 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)); glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax));
state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation;
state.rotation = newRotation; state.rotation = newRotation;
state.animationDisabled = true;
} }
const int BALL_SUBDIVISIONS = 10; const int BALL_SUBDIVISIONS = 10;
@ -1749,8 +1765,9 @@ void AnimationHandle::simulate(float deltaTime) {
int mapping = _jointMappings.at(i); int mapping = _jointMappings.at(i);
if (mapping != -1) { if (mapping != -1) {
Model::JointState& state = _model->_jointStates[mapping]; Model::JointState& state = _model->_jointStates[mapping];
if (!state.animationDisabled) { if (_priority >= state.animationPriority) {
state.rotation = frame.rotations.at(i); state.rotation = frame.rotations.at(i);
state.animationPriority = _priority;
} }
} }
} }
@ -1772,8 +1789,9 @@ void AnimationHandle::simulate(float deltaTime) {
int mapping = _jointMappings.at(i); int mapping = _jointMappings.at(i);
if (mapping != -1) { if (mapping != -1) {
Model::JointState& state = _model->_jointStates[mapping]; 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.rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
state.animationPriority = _priority;
} }
} }
} }

View file

@ -113,7 +113,7 @@ public:
bool getJointState(int index, glm::quat& rotation) const; bool getJointState(int index, glm::quat& rotation) const;
/// Sets the joint state at the specified index. /// 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. /// Returns the index of the left hand joint, or -1 if not found.
int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } 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. /// Restores some percentage of the default position of the left hand.
/// \param percent the percentage of the default position to restore /// \param percent the percentage of the default position to restore
/// \return whether or not the left hand joint was found /// \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. /// Gets the position of the left shoulder.
/// \return whether or not the left shoulder joint was found /// \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. /// Restores some percentage of the default position of the right hand.
/// \param percent the percentage of the default position to restore /// \param percent the percentage of the default position to restore
/// \return whether or not the right hand joint was found /// \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. /// Gets the position of the right shoulder.
/// \return whether or not the right shoulder joint was found /// \return whether or not the right shoulder joint was found
@ -254,7 +254,7 @@ protected:
glm::quat rotation; // rotation relative to parent glm::quat rotation; // rotation relative to parent
glm::mat4 transform; // rotation to world frame + translation in model frame glm::mat4 transform; // rotation to world frame + translation in model frame
glm::quat combinedRotation; // rotation from joint local to world 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; bool _shapesAreDirty;
@ -290,8 +290,8 @@ protected:
bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(),
bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false,
const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); 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); bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false, float priority = 1.0f);
void setJointTranslation(int jointIndex, const glm::vec3& translation); 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 /// \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 /// the original position
/// \return true if the joint was found /// \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 /// Computes and returns the extended length of the limb terminating at the specified joint and starting at the joint's
/// first free ancestor. /// first free ancestor.
float getLimbLength(int jointIndex) const; 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); void computeBoundingShape(const FBXGeometry& geometry);

View file

@ -10,6 +10,7 @@
// //
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QFileDialog> #include <QFileDialog>
@ -80,6 +81,9 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePo
layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
setLayout(layout); setLayout(layout);
layout->addRow("Role:", _role = new QComboBox());
_role->setEditable(true);
QHBoxLayout* urlBox = new QHBoxLayout(); QHBoxLayout* urlBox = new QHBoxLayout();
layout->addRow("URL:", urlBox); layout->addRow("URL:", urlBox);
urlBox->addWidget(_url = new QLineEdit(handle->getURL().toString()), 1); urlBox->addWidget(_url = new QLineEdit(handle->getURL().toString()), 1);

View file

@ -18,6 +18,7 @@
#include "avatar/MyAvatar.h" #include "avatar/MyAvatar.h"
class QCheckBox; class QCheckBox;
class QComboBox;
class QDoubleSpinner; class QDoubleSpinner;
class QLineEdit; class QLineEdit;
class QPushButton; class QPushButton;
@ -63,6 +64,7 @@ private:
AnimationsDialog* _dialog; AnimationsDialog* _dialog;
AnimationHandlePointer _handle; AnimationHandlePointer _handle;
QComboBox* _role;
QLineEdit* _url; QLineEdit* _url;
QDoubleSpinBox* _fps; QDoubleSpinBox* _fps;
QDoubleSpinBox* _priority; QDoubleSpinBox* _priority;