JS scripts set joint animation priorities

This commit is contained in:
Andrew Meadows 2014-08-20 17:14:59 -07:00
parent a01d3781d9
commit 7e4c72445e
8 changed files with 56 additions and 34 deletions

View file

@ -3821,6 +3821,10 @@ void Application::stopAllScripts(bool restart) {
it.value()->stop(); it.value()->stop();
qDebug() << "stopping script..." << it.key(); 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) { void Application::stopScript(const QString &scriptName) {
@ -3828,6 +3832,10 @@ void Application::stopScript(const QString &scriptName) {
if (_scriptEnginesHash.contains(scriptURLString)) { if (_scriptEnginesHash.contains(scriptURLString)) {
_scriptEnginesHash.value(scriptURLString)->stop(); _scriptEnginesHash.value(scriptURLString)->stop();
qDebug() << "stopping script..." << scriptName; 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();
} }
} }

View file

@ -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])) 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->getFinalYaw(), glm::normalize(inverse * axes[1]))
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0])) * 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) { 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); glm::quat between = rotationBetween(front, lookAt);
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; 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)) * 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) { void FaceModel::updateJointState(int index) {

View file

@ -992,36 +992,39 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const {
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f); 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<glm::quat> jointRotations) { void MyAvatar::setJointRotations(QVector<glm::quat> jointRotations) {
for (int i = 0; i < jointRotations.size(); ++i) { int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size());
if (i < _jointData.size()) { for (int i = 0; i < numStates; ++i) {
_skeletonModel.setJointState(i, true, jointRotations[i], JOINT_PRIORITY + 1.0f); // 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) { void MyAvatar::setJointData(int index, const glm::quat& rotation) {
Avatar::setJointData(index, rotation);
if (QThread::currentThread() == thread()) { 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) { void MyAvatar::clearJointData(int index) {
Avatar::clearJointData(index);
if (QThread::currentThread() == thread()) { 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() { void MyAvatar::clearJointsData() {
for (int i = 0; i < _jointData.size(); ++i) { clearJointAnimationPriorities();
Avatar::clearJointData(i); }
if (QThread::currentThread() == thread()) {
_skeletonModel.clearJointAnimationPriority(i); void MyAvatar::clearJointAnimationPriorities() {
} int numStates = _skeletonModel.getJointStateCount();
for (int i = 0; i < numStates; ++i) {
_skeletonModel.clearJointAnimationPriority(i);
} }
} }

View file

@ -128,6 +128,8 @@ public:
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData); virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
void clearJointAnimationPriorities();
virtual void attach(const QString& modelURL, const QString& jointName = QString(), 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, const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f,
bool allowDuplicates = false, bool useSaved = true); bool allowDuplicates = false, bool useSaved = true);

View file

@ -51,7 +51,8 @@ void SkeletonModel::setJointStates(QVector<JointState> 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) { void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
setTranslation(_owningAvatar->getPosition()); setTranslation(_owningAvatar->getPosition());
@ -230,7 +231,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
JointState& parentState = _jointStates[parentJointIndex]; JointState& parentState = _jointStates[parentJointIndex];
parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY); parentState.setRotationInBindFrame(palmRotation, PALM_PRIORITY);
// lock hand to forearm by slamming its rotation (in parent-frame) to identity // 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 { } else {
inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY);
} }
@ -271,7 +272,7 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, Joint
state.setRotationInConstrainedFrame( state.setRotationInConstrainedFrame(
glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), inverse * zAxis) glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), inverse * zAxis)
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), inverse * xAxis) * 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) { void SkeletonModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {

View file

@ -145,7 +145,7 @@ glm::quat JointState::getVisibleRotationInParentFrame() const {
void JointState::restoreRotation(float fraction, float priority) { void JointState::restoreRotation(float fraction, float priority) {
assert(_fbxJoint != NULL); assert(_fbxJoint != NULL);
if (priority == _animationPriority || _animationPriority == 0.0f) { if (priority == _animationPriority || _animationPriority == 0.0f) {
setRotationInConstrainedFrame(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction)); setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction));
_animationPriority = 0.0f; _animationPriority = 0.0f;
} }
} }
@ -158,7 +158,7 @@ void JointState::setRotationInBindFrame(const glm::quat& rotation, float priorit
if (constrain && _constraint) { if (constrain && _constraint) {
_constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);
} }
setRotationInConstrainedFrame(targetRotation); setRotationInConstrainedFrameInternal(targetRotation);
_animationPriority = priority; _animationPriority = priority;
} }
} }
@ -189,7 +189,7 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa
_rotation = delta * getRotation(); _rotation = delta * getRotation();
return; return;
} }
setRotationInConstrainedFrame(targetRotation); setRotationInConstrainedFrameInternal(targetRotation);
} }
/// Applies delta rotation to joint but mixes a little bit of the default pose as well. /// 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) { if (_constraint) {
_constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f);
} }
setRotationInConstrainedFrame(targetRotation); setRotationInConstrainedFrameInternal(targetRotation);
} }
void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor) { 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); 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(); glm::quat parentRotation = computeParentRotation();
_rotationInConstrainedFrame = targetRotation; _rotationInConstrainedFrame = targetRotation;
_transformChanged = true; _transformChanged = true;

View file

@ -19,6 +19,8 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <FBXReader.h> #include <FBXReader.h>
const float DEFAULT_PRIORITY = 3.0f;
class AngularConstraint; class AngularConstraint;
class JointState { class JointState {
@ -81,7 +83,7 @@ public:
/// NOTE: the JointState's model-frame transform/rotation are NOT updated! /// NOTE: the JointState's model-frame transform/rotation are NOT updated!
void setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain = false); 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); void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation);
const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; } const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; }
const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; } const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; }
@ -104,6 +106,7 @@ public:
glm::quat computeVisibleParentRotation() const; glm::quat computeVisibleParentRotation() const;
private: private:
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
/// debug helper function /// debug helper function
void loadBindRotation(); void loadBindRotation();

View file

@ -438,7 +438,7 @@ void Model::reset() {
} }
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
for (int i = 0; i < _jointStates.size(); i++) { 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) { void Model::clearJointState(int index) {
if (index != -1 && index < _jointStates.size()) { if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index]; JointState& state = _jointStates[index];
state.setRotationInConstrainedFrame(glm::quat()); state.setRotationInConstrainedFrame(glm::quat(), 0.0f);
state._animationPriority = 0.0f;
} }
} }
@ -711,8 +710,7 @@ void Model::setJointState(int index, bool valid, const glm::quat& rotation, floa
JointState& state = _jointStates[index]; JointState& state = _jointStates[index];
if (priority >= state._animationPriority) { if (priority >= state._animationPriority) {
if (valid) { if (valid) {
state.setRotationInConstrainedFrame(rotation); state.setRotationInConstrainedFrame(rotation, priority);
state._animationPriority = priority;
} else { } else {
state.restoreRotation(1.0f, priority); state.restoreRotation(1.0f, priority);
} }
@ -1745,10 +1743,7 @@ void AnimationHandle::applyFrame(float frameIndex) {
int mapping = _jointMappings.at(i); int mapping = _jointMappings.at(i);
if (mapping != -1) { if (mapping != -1) {
JointState& state = _model->_jointStates[mapping]; JointState& state = _model->_jointStates[mapping];
if (_priority >= state._animationPriority) { state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction), _priority);
state.setRotationInConstrainedFrame(safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction));
state._animationPriority = _priority;
}
} }
} }
} }