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) {
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);
}
}

View file

@ -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);
}

View file

@ -118,7 +118,7 @@ QVector<Model::JointState> 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;
}
}
}

View file

@ -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);

View file

@ -10,6 +10,7 @@
//
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFileDialog>
@ -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);

View file

@ -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;