From 42cc34cd64dae1e8d9edd129ae0d83f88c420e44 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 6 Aug 2015 16:54:09 -0700 Subject: [PATCH 1/3] JointState has our own copy of any ivars we want from FBXJoint, instead of keeping a reference to the fbx. --- interface/src/avatar/FaceModel.cpp | 22 +++--- interface/src/avatar/FaceModel.h | 4 +- interface/src/avatar/SkeletonModel.cpp | 13 ++-- libraries/animation/src/AvatarRig.cpp | 7 +- libraries/animation/src/EntityRig.cpp | 5 +- libraries/animation/src/JointState.cpp | 101 ++++++++++++++++--------- libraries/animation/src/JointState.h | 29 ++++++- libraries/animation/src/Rig.cpp | 32 ++++---- tests/animation/src/RigTests.cpp | 2 +- 9 files changed, 131 insertions(+), 84 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 066144a425..22ba7455b8 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -56,12 +56,12 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { } } -void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index) { +void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index) { // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(glm::quat()); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation))); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame()); glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(), _owningHead->getTorsoTwist(), @@ -71,15 +71,15 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) - * joint.rotation, DEFAULT_PRIORITY); + * state.getOriginalRotation(), DEFAULT_PRIORITY); } -void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index) { +void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index) { // likewise with the eye joints // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getOriginalRotation())); glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); @@ -87,22 +87,22 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - joint.rotation, DEFAULT_PRIORITY); + state.getOriginalRotation(), DEFAULT_PRIORITY); } void FaceModel::maybeUpdateNeckAndEyeRotation(int index) { const JointState& state = _rig->getJointState(index); - const FBXJoint& joint = state.getFBXJoint(); const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const int parentIndex = state.getParentIndex(); // guard against out-of-bounds access to _jointStates - if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _rig->getJointStateCount()) { - const JointState& parentState = _rig->getJointState(joint.parentIndex); + if (parentIndex != -1 && parentIndex >= 0 && parentIndex < _rig->getJointStateCount()) { + const JointState& parentState = _rig->getJointState(parentIndex); if (index == geometry.neckJointIndex) { - maybeUpdateNeckRotation(parentState, joint, index); + maybeUpdateNeckRotation(parentState, state, index); } else if (index == geometry.leftEyeJointIndex || index == geometry.rightEyeJointIndex) { - maybeUpdateEyeRotation(this, parentState, joint, index); + maybeUpdateEyeRotation(this, parentState, state, index); } } } diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 54d685c73c..ed1ea28508 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -26,8 +26,8 @@ public: virtual void simulate(float deltaTime, bool fullUpdate = true); - void maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, int index); - void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, int index); + void maybeUpdateNeckRotation(const JointState& parentState, const JointState& state, int index); + void maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index); void maybeUpdateNeckAndEyeRotation(int index); /// Retrieve the positions of up to two eye meshes. diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d5cb0517a7..8000ed8d26 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -401,7 +401,7 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP glm::quat worldFrameRotation; bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); if (success) { - neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getFBXJoint().inverseDefaultRotation; + neckParentRotation = worldFrameRotation * _rig->getJointState(parentIndex).getInverseDefaultRotation(); } return success; } @@ -477,18 +477,17 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { for (int i = 0; i < numStates; i++) { // compute the default transform of this joint const JointState& state = _rig->getJointState(i); - const FBXJoint& joint = state.getFBXJoint(); - int parentIndex = joint.parentIndex; + int parentIndex = state.getParentIndex(); if (parentIndex == -1) { transforms[i] = _rig->getJointTransform(i); } else { - glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; - transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) - * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; + glm::quat modifiedRotation = state.getPreRotation() * state.getOriginalRotation() * state.getPostRotation(); + transforms[i] = transforms[parentIndex] * glm::translate(state.getTranslation()) + * state.getPreTransform() * glm::mat4_cast(modifiedRotation) * state.getPostTransform(); } // Each joint contributes a sphere at its position - glm::vec3 axis(joint.boneRadius); + glm::vec3 axis(state.getBoneRadius()); glm::vec3 jointPosition = extractTranslation(transforms[i]); totalExtents.addPoint(jointPosition + axis); totalExtents.addPoint(jointPosition - axis); diff --git a/libraries/animation/src/AvatarRig.cpp b/libraries/animation/src/AvatarRig.cpp index 97fbb82944..ebf0a8795e 100644 --- a/libraries/animation/src/AvatarRig.cpp +++ b/libraries/animation/src/AvatarRig.cpp @@ -17,7 +17,6 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) { return; // bail } JointState& state = _jointStates[index]; - const FBXJoint& joint = state.getFBXJoint(); // compute model transforms if (index == _rootJointIndex) { @@ -26,7 +25,7 @@ void AvatarRig::updateJointState(int index, glm::mat4 parentTransform) { clearJointTransformTranslation(index); } else { // guard against out-of-bounds access to _jointStates - int parentIndex = joint.parentIndex; + int parentIndex = state.getParentIndex(); if (parentIndex >= 0 && parentIndex < _jointStates.size()) { const JointState& parentState = _jointStates.at(parentIndex); state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); @@ -53,8 +52,8 @@ void AvatarRig::setHandPosition(int jointIndex, } // precomputed lengths - float upperArmLength = _jointStates[elbowJointIndex].getFBXJoint().distanceToParent * scale; - float lowerArmLength = _jointStates[jointIndex].getFBXJoint().distanceToParent * scale; + float upperArmLength = _jointStates[elbowJointIndex].getDistanceToParent() * scale; + float lowerArmLength = _jointStates[jointIndex].getDistanceToParent() * scale; // first set wrist position glm::vec3 wristPosition = position; diff --git a/libraries/animation/src/EntityRig.cpp b/libraries/animation/src/EntityRig.cpp index 5ed1799671..eddbdd6464 100644 --- a/libraries/animation/src/EntityRig.cpp +++ b/libraries/animation/src/EntityRig.cpp @@ -14,15 +14,14 @@ /// Updates the state of the joint at the specified index. void EntityRig::updateJointState(int index, glm::mat4 parentTransform) { JointState& state = _jointStates[index]; - const FBXJoint& joint = state.getFBXJoint(); // compute model transforms - int parentIndex = joint.parentIndex; + int parentIndex = state.getParentIndex(); if (parentIndex == -1) { state.computeTransform(parentTransform); } else { // guard against out-of-bounds access to _jointStates - if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { + if (parentIndex >= 0 && parentIndex < _jointStates.size()) { const JointState& parentState = _jointStates.at(parentIndex); state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); } diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index 3682837719..f867369c1d 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -24,7 +24,6 @@ JointState::JointState() : _rotationIsValid(false), _positionInParentFrame(0.0f), _distanceToParent(0.0f), - _fbxJoint(NULL), _constraint(NULL) { } @@ -37,8 +36,21 @@ JointState::JointState(const JointState& other) : _constraint(NULL) { _positionInParentFrame = other._positionInParentFrame; _distanceToParent = other._distanceToParent; _animationPriority = other._animationPriority; - _fbxJoint = other._fbxJoint; // DO NOT copy _constraint + _name = other._name; + _isFree = other._isFree; + _boneRadius = other._boneRadius; + _parentIndex = other._parentIndex; + _translation = other._translation; + _originalRotation = other._originalRotation; + _inverseDefaultRotation = other._inverseDefaultRotation; + _rotationMin = other._rotationMin; + _rotationMax = other._rotationMax; + _preRotation = other._preRotation; + _postRotation = other._postRotation; + _preTransform = other._preTransform; + _postTransform = other._postTransform; + _inverseBindRotation = other._inverseBindRotation; } JointState::~JointState() { @@ -65,8 +77,20 @@ void JointState::setFBXJoint(const FBXJoint* joint) { _transformChanged = true; _rotationIsValid = false; - // NOTE: JointState does not own the FBXJoint to which it points. - _fbxJoint = joint; + _name = joint->name; + _isFree = joint->isFree; + _boneRadius = joint->boneRadius; + _parentIndex = joint->parentIndex; + _translation = joint->translation; + _originalRotation = joint->rotation; + _inverseDefaultRotation = joint->inverseDefaultRotation; + _rotationMin = joint->rotationMin; + _rotationMax = joint->rotationMax; + _preRotation = joint->preRotation; + _postRotation = joint->postRotation; + _preTransform = joint->preTransform; + _postTransform = joint->postTransform; + _inverseBindRotation = joint->inverseBindRotation; if (_constraint) { delete _constraint; _constraint = NULL; @@ -78,10 +102,10 @@ void JointState::buildConstraint() { delete _constraint; _constraint = NULL; } - if (glm::distance2(glm::vec3(-PI), _fbxJoint->rotationMin) > EPSILON || - glm::distance2(glm::vec3(PI), _fbxJoint->rotationMax) > EPSILON ) { + if (glm::distance2(glm::vec3(-PI), _rotationMin) > EPSILON || + glm::distance2(glm::vec3(PI), _rotationMax) > EPSILON ) { // this joint has rotation constraints - _constraint = AngularConstraint::newAngularConstraint(_fbxJoint->rotationMin, _fbxJoint->rotationMax); + _constraint = AngularConstraint::newAngularConstraint(_rotationMin, _rotationMax); } } @@ -98,7 +122,21 @@ void JointState::copyState(const JointState& state) { _visibleTransform = state._visibleTransform; _visibleRotation = extractRotation(_visibleTransform); _visibleRotationInConstrainedFrame = state._visibleRotationInConstrainedFrame; - // DO NOT copy _fbxJoint or _constraint + // DO NOT copy _constraint + _name = state._name; + _isFree = state._isFree; + _boneRadius = state._boneRadius; + _parentIndex = state._parentIndex; + _originalRotation = state._originalRotation; + _inverseDefaultRotation = state._inverseDefaultRotation; + _translation = state._translation; + _rotationMin = state._rotationMin; + _rotationMax = state._rotationMax; + _preRotation = state._preRotation; + _postRotation = state._postRotation; + _preTransform = state._preTransform; + _postTransform = state._postTransform; + _inverseBindRotation = state._inverseBindRotation; } void JointState::initTransform(const glm::mat4& parentTransform) { @@ -112,9 +150,9 @@ void JointState::computeTransform(const glm::mat4& parentTransform, bool parentT return; } - glm::quat rotationInParentFrame = _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation; - glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform; - glm::mat4 newTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame; + glm::quat rotationInParentFrame = _preRotation * _rotationInConstrainedFrame * _postRotation; + glm::mat4 transformInParentFrame = _preTransform * glm::mat4_cast(rotationInParentFrame) * _postTransform; + glm::mat4 newTransform = parentTransform * glm::translate(_translation) * transformInParentFrame; if (newTransform != _transform) { _transform = newTransform; @@ -124,37 +162,35 @@ void JointState::computeTransform(const glm::mat4& parentTransform, bool parentT } void JointState::computeVisibleTransform(const glm::mat4& parentTransform) { - glm::quat rotationInParentFrame = _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation; - glm::mat4 transformInParentFrame = _fbxJoint->preTransform * glm::mat4_cast(rotationInParentFrame) * _fbxJoint->postTransform; - _visibleTransform = parentTransform * glm::translate(_fbxJoint->translation) * transformInParentFrame; + glm::quat rotationInParentFrame = _preRotation * _visibleRotationInConstrainedFrame * _postRotation; + glm::mat4 transformInParentFrame = _preTransform * glm::mat4_cast(rotationInParentFrame) * _postTransform; + _visibleTransform = parentTransform * glm::translate(_translation) * transformInParentFrame; _visibleRotation = extractRotation(_visibleTransform); } glm::quat JointState::getRotationInBindFrame() const { - return getRotation() * _fbxJoint->inverseBindRotation; + return getRotation() * _inverseBindRotation; } glm::quat JointState::getRotationInParentFrame() const { - return _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation; + return _preRotation * _rotationInConstrainedFrame * _postRotation; } glm::quat JointState::getVisibleRotationInParentFrame() const { - return _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation; + return _preRotation * _visibleRotationInConstrainedFrame * _postRotation; } void JointState::restoreRotation(float fraction, float priority) { - assert(_fbxJoint != NULL); if (priority == _animationPriority || _animationPriority == 0.0f) { - setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _fbxJoint->rotation, fraction)); + setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _originalRotation, fraction)); _animationPriority = 0.0f; } } void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority, bool constrain) { // rotation is from bind- to model-frame - assert(_fbxJoint != NULL); if (priority >= _animationPriority) { - glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_inverseBindRotation); if (constrain && _constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); } @@ -175,7 +211,6 @@ void JointState::clearTransformTranslation() { void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) { // NOTE: delta is in model-frame - assert(_fbxJoint != NULL); if (priority < _animationPriority || delta == glm::quat()) { return; } @@ -196,14 +231,13 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa /// This helps keep an IK solution stable. void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float priority) { // NOTE: delta is in model-frame - assert(_fbxJoint != NULL); if (priority < _animationPriority) { return; } _animationPriority = priority; glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation(); if (mixFactor > 0.0f && mixFactor <= 1.0f) { - targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor); + targetRotation = safeMix(targetRotation, _originalRotation, mixFactor); } if (_constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); @@ -213,10 +247,8 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor) { // NOTE: delta is in model-frame - assert(_fbxJoint != NULL); glm::quat targetRotation = _visibleRotationInConstrainedFrame * glm::inverse(_visibleRotation) * delta * _visibleRotation; if (mixFactor > 0.0f && mixFactor <= 1.0f) { - //targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor); targetRotation = safeMix(targetRotation, _rotationInConstrainedFrame, mixFactor); } setVisibleRotationInConstrainedFrame(targetRotation); @@ -225,11 +257,11 @@ void JointState::mixVisibleRotationDelta(const glm::quat& delta, float mixFactor glm::quat JointState::computeParentRotation() const { // R = Rp * Rpre * r * Rpost // Rp = R * (Rpre * r * Rpost)^ - return getRotation() * glm::inverse(_fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation); + return getRotation() * glm::inverse(_preRotation * _rotationInConstrainedFrame * _postRotation); } glm::quat JointState::computeVisibleParentRotation() const { - return _visibleRotation * glm::inverse(_fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation); + return _visibleRotation * glm::inverse(_preRotation * _visibleRotationInConstrainedFrame * _postRotation); } void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, bool constrain, float mix) { @@ -248,17 +280,17 @@ void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRo _rotationInConstrainedFrame = targetRotation; _transformChanged = true; // R' = Rp * Rpre * r' * Rpost - _rotation = parentRotation * _fbxJoint->preRotation * _rotationInConstrainedFrame * _fbxJoint->postRotation; + _rotation = parentRotation * _preRotation * _rotationInConstrainedFrame * _postRotation; } void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation) { glm::quat parentRotation = computeVisibleParentRotation(); _visibleRotationInConstrainedFrame = targetRotation; - _visibleRotation = parentRotation * _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation; + _visibleRotation = parentRotation * _preRotation * _visibleRotationInConstrainedFrame * _postRotation; } bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const { - glm::quat defaultRotation = _fbxJoint->rotation; + glm::quat defaultRotation = _originalRotation; return glm::abs(rotation.x - defaultRotation.x) < tolerance && glm::abs(rotation.y - defaultRotation.y) < tolerance && glm::abs(rotation.z - defaultRotation.z) < tolerance && @@ -266,13 +298,12 @@ bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) c } glm::quat JointState::getDefaultRotationInParentFrame() const { - // NOTE: the result is constant and could be cached in the FBXJoint - return _fbxJoint->preRotation * _fbxJoint->rotation * _fbxJoint->postRotation; + // NOTE: the result is constant and could be cached + return _preRotation * _originalRotation * _postRotation; } const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const { - assert(_fbxJoint != NULL); - return _fbxJoint->translation; + return _translation; } void JointState::slaveVisibleTransform() { diff --git a/libraries/animation/src/JointState.h b/libraries/animation/src/JointState.h index 93bf83d2c4..d7e954d59c 100644 --- a/libraries/animation/src/JointState.h +++ b/libraries/animation/src/JointState.h @@ -31,7 +31,6 @@ public: ~JointState(); void setFBXJoint(const FBXJoint* joint); - const FBXJoint& getFBXJoint() const { return *_fbxJoint; } void buildConstraint(); void copyState(const JointState& state); @@ -61,7 +60,7 @@ public: const glm::vec3& getPositionInParentFrame() const { return _positionInParentFrame; } float getDistanceToParent() const { return _distanceToParent; } - int getParentIndex() const { return _fbxJoint->parentIndex; } + int getParentIndex() const { return _parentIndex; } /// \param delta is in the model-frame void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f); @@ -108,6 +107,17 @@ public: void setTransform(const glm::mat4& transform) { _transform = transform; } void setVisibleTransform(const glm::mat4& transform) { _visibleTransform = transform; } + + const glm::vec3& getTranslation() const { return _translation; } + const glm::mat4& getPreTransform() const { return _preTransform; } + const glm::mat4& getPostTransform() const { return _postTransform; } + const glm::quat& getPreRotation() const { return _preRotation; } + const glm::quat& getPostRotation() const { return _postRotation; } + const glm::quat& getOriginalRotation() const { return _originalRotation; } + const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; } + const QString& getName() const { return _name; } + float getBoneRadius() const { return _boneRadius; } + bool getIsFree() const { return _isFree; } private: void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation); @@ -126,7 +136,20 @@ private: glm::quat _visibleRotation; glm::quat _visibleRotationInConstrainedFrame; - const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint + glm::quat _originalRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform + glm::quat _inverseDefaultRotation; + glm::vec3 _translation; + float _boneRadius; + bool _isFree; + glm::vec3 _rotationMin; + glm::vec3 _rotationMax; + glm::quat _preRotation; + glm::quat _postRotation; + glm::mat4 _preTransform; + glm::mat4 _postTransform; + glm::quat _inverseBindRotation; + int _parentIndex; + QString _name; AngularConstraint* _constraint; // JointState owns its AngularConstraint }; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index ec34e90b5c..1c7257adc7 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -222,7 +222,7 @@ float Rig::initJointStates(QVector states, glm::mat4 parentTransform // Should we be using .fst mapping instead/also? int Rig::indexOfJoint(const QString& jointName) { for (int i = 0; i < _jointStates.count(); i++) { - if (_jointStates[i].getFBXJoint().name == jointName) { + if (_jointStates[i].getName() == jointName) { return i; } } @@ -235,8 +235,7 @@ void Rig::initJointTransforms(glm::mat4 parentTransform) { int numStates = _jointStates.size(); for (int i = 0; i < numStates; ++i) { JointState& state = _jointStates[i]; - const FBXJoint& joint = state.getFBXJoint(); - int parentIndex = joint.parentIndex; + int parentIndex = state.getParentIndex(); if (parentIndex == -1) { state.initTransform(parentTransform); } else { @@ -528,8 +527,7 @@ bool Rig::setJointPosition(int jointIndex, const glm::vec3& position, const glm: for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); JointState& state = _jointStates[index]; - const FBXJoint& joint = state.getFBXJoint(); - if (!(joint.isFree || allIntermediatesFree)) { + if (!(state.getIsFree() || allIntermediatesFree)) { continue; } glm::vec3 jointPosition = extractTranslation(state.getTransform()); @@ -598,8 +596,7 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q { int index = freeLineage.last(); const JointState& state = _jointStates.at(index); - const FBXJoint& joint = state.getFBXJoint(); - int parentIndex = joint.parentIndex; + int parentIndex = state.getParentIndex(); if (parentIndex == -1) { topParentTransform = parentTransform; } else { @@ -624,8 +621,7 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q for (int j = 1; j < numFree; j++) { int nextIndex = freeLineage.at(j); JointState& nextState = _jointStates[nextIndex]; - FBXJoint nextJoint = nextState.getFBXJoint(); - if (! nextJoint.isFree) { + if (! nextState.getIsFree()) { continue; } @@ -799,20 +795,20 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) * glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) * glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) * - getJointState(index).getFBXJoint().rotation, DEFAULT_PRIORITY); + getJointState(index).getOriginalRotation(), DEFAULT_PRIORITY); } } void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { - auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; - auto joint = _jointStates[index].getFBXJoint(); + auto& state = _jointStates[index]; + auto& parentState = _jointStates[state.getParentIndex()]; // get the rotation axes in joint space and use them to adjust the rotation glm::mat3 axes = glm::mat3_cast(glm::quat()); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation))); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); glm::vec3 pitchYawRoll = safeEulerAngles(localHeadOrientation); glm::vec3 lean = glm::radians(glm::vec3(leanForward, torsoTwist, leanSideways)); pitchYawRoll -= lean; @@ -820,19 +816,19 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) * - joint.rotation, DEFAULT_PRIORITY); + state.getOriginalRotation(), DEFAULT_PRIORITY); } } void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { - auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; - auto joint = _jointStates[index].getFBXJoint(); + auto& state = _jointStates[index]; + auto& parentState = _jointStates[state.getParentIndex()]; // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. glm::mat4 inverse = glm::inverse(parentState.getTransform() * glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * - joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getOriginalRotation())); glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAtDelta = lookAt; glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f)); @@ -840,6 +836,6 @@ void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; float angle = glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE); glm::quat rot = glm::angleAxis(angle, glm::axis(between)); - setJointRotationInConstrainedFrame(index, rot * joint.rotation, DEFAULT_PRIORITY); + setJointRotationInConstrainedFrame(index, rot * state.getOriginalRotation(), DEFAULT_PRIORITY); } } diff --git a/tests/animation/src/RigTests.cpp b/tests/animation/src/RigTests.cpp index 8dbba30031..79c2f3b5df 100644 --- a/tests/animation/src/RigTests.cpp +++ b/tests/animation/src/RigTests.cpp @@ -79,7 +79,7 @@ void RigTests::initTestCase() { static void reportJoint(int index, JointState joint) { // Handy for debugging std::cout << "\n"; - std::cout << index << " " << joint.getFBXJoint().name.toUtf8().data() << "\n"; + std::cout << index << " " << joint.getName.toUtf8().data() << "\n"; std::cout << " pos:" << joint.getPosition() << "/" << joint.getPositionInParentFrame() << " from " << joint.getParentIndex() << "\n"; std::cout << " rot:" << safeEulerAngles(joint.getRotation()) << "/" << safeEulerAngles(joint.getRotationInParentFrame()) << "/" << safeEulerAngles(joint.getRotationInBindFrame()) << "\n"; std::cout << "\n"; From a840a17106475fa284870f6d1c7e7cdcea07316a Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 6 Aug 2015 19:45:58 -0700 Subject: [PATCH 2/3] Change name originalRotation defaultRotation. --- interface/src/avatar/FaceModel.cpp | 6 +++--- interface/src/avatar/SkeletonModel.cpp | 2 +- libraries/animation/src/JointState.cpp | 14 +++++++------- libraries/animation/src/JointState.h | 4 ++-- libraries/animation/src/Rig.cpp | 8 ++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 22ba7455b8..e31c804185 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -71,7 +71,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const Joi glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) - * state.getOriginalRotation(), DEFAULT_PRIORITY); + * state.getDefaultRotation(), DEFAULT_PRIORITY); } void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const JointState& state, int index) { @@ -79,7 +79,7 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. glm::mat4 inverse = glm::inverse(glm::mat4_cast(model->getRotation()) * parentState.getTransform() * glm::translate(_rig->getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getOriginalRotation())); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation())); glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientationInWorldFrame() * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAtDelta = _owningHead->getCorrectedLookAtPosition() - model->getTranslation(); glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * _owningHead->getSaccade(), 1.0f)); @@ -87,7 +87,7 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; _rig->setJointRotationInConstrainedFrame(index, glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * - state.getOriginalRotation(), DEFAULT_PRIORITY); + state.getDefaultRotation(), DEFAULT_PRIORITY); } void FaceModel::maybeUpdateNeckAndEyeRotation(int index) { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8000ed8d26..dab7770a09 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -481,7 +481,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { if (parentIndex == -1) { transforms[i] = _rig->getJointTransform(i); } else { - glm::quat modifiedRotation = state.getPreRotation() * state.getOriginalRotation() * state.getPostRotation(); + glm::quat modifiedRotation = state.getPreRotation() * state.getDefaultRotation() * state.getPostRotation(); transforms[i] = transforms[parentIndex] * glm::translate(state.getTranslation()) * state.getPreTransform() * glm::mat4_cast(modifiedRotation) * state.getPostTransform(); } diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index f867369c1d..c81aae468d 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -42,7 +42,7 @@ JointState::JointState(const JointState& other) : _constraint(NULL) { _boneRadius = other._boneRadius; _parentIndex = other._parentIndex; _translation = other._translation; - _originalRotation = other._originalRotation; + _defaultRotation = other._defaultRotation; _inverseDefaultRotation = other._inverseDefaultRotation; _rotationMin = other._rotationMin; _rotationMax = other._rotationMax; @@ -82,7 +82,7 @@ void JointState::setFBXJoint(const FBXJoint* joint) { _boneRadius = joint->boneRadius; _parentIndex = joint->parentIndex; _translation = joint->translation; - _originalRotation = joint->rotation; + _defaultRotation = joint->rotation; _inverseDefaultRotation = joint->inverseDefaultRotation; _rotationMin = joint->rotationMin; _rotationMax = joint->rotationMax; @@ -127,7 +127,7 @@ void JointState::copyState(const JointState& state) { _isFree = state._isFree; _boneRadius = state._boneRadius; _parentIndex = state._parentIndex; - _originalRotation = state._originalRotation; + _defaultRotation = state._defaultRotation; _inverseDefaultRotation = state._inverseDefaultRotation; _translation = state._translation; _rotationMin = state._rotationMin; @@ -182,7 +182,7 @@ glm::quat JointState::getVisibleRotationInParentFrame() const { void JointState::restoreRotation(float fraction, float priority) { if (priority == _animationPriority || _animationPriority == 0.0f) { - setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _originalRotation, fraction)); + setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _defaultRotation, fraction)); _animationPriority = 0.0f; } } @@ -237,7 +237,7 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float _animationPriority = priority; glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation(); if (mixFactor > 0.0f && mixFactor <= 1.0f) { - targetRotation = safeMix(targetRotation, _originalRotation, mixFactor); + targetRotation = safeMix(targetRotation, _defaultRotation, mixFactor); } if (_constraint) { _constraint->softClamp(targetRotation, _rotationInConstrainedFrame, 0.5f); @@ -290,7 +290,7 @@ void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRot } bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const { - glm::quat defaultRotation = _originalRotation; + glm::quat defaultRotation = _defaultRotation; return glm::abs(rotation.x - defaultRotation.x) < tolerance && glm::abs(rotation.y - defaultRotation.y) < tolerance && glm::abs(rotation.z - defaultRotation.z) < tolerance && @@ -299,7 +299,7 @@ bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) c glm::quat JointState::getDefaultRotationInParentFrame() const { // NOTE: the result is constant and could be cached - return _preRotation * _originalRotation * _postRotation; + return _preRotation * _defaultRotation * _postRotation; } const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const { diff --git a/libraries/animation/src/JointState.h b/libraries/animation/src/JointState.h index d7e954d59c..51f92f3ace 100644 --- a/libraries/animation/src/JointState.h +++ b/libraries/animation/src/JointState.h @@ -113,7 +113,7 @@ public: const glm::mat4& getPostTransform() const { return _postTransform; } const glm::quat& getPreRotation() const { return _preRotation; } const glm::quat& getPostRotation() const { return _postRotation; } - const glm::quat& getOriginalRotation() const { return _originalRotation; } + const glm::quat& getDefaultRotation() const { return _defaultRotation; } const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; } const QString& getName() const { return _name; } float getBoneRadius() const { return _boneRadius; } @@ -136,7 +136,7 @@ private: glm::quat _visibleRotation; glm::quat _visibleRotationInConstrainedFrame; - glm::quat _originalRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform + glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform glm::quat _inverseDefaultRotation; glm::vec3 _translation; float _boneRadius; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 1c7257adc7..207cb5e4e1 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -795,7 +795,7 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) * glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) * glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) * - getJointState(index).getOriginalRotation(), DEFAULT_PRIORITY); + getJointState(index).getDefaultRotation(), DEFAULT_PRIORITY); } } @@ -816,7 +816,7 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) * - state.getOriginalRotation(), DEFAULT_PRIORITY); + state.getDefaultRotation(), DEFAULT_PRIORITY); } } @@ -828,7 +828,7 @@ void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. glm::mat4 inverse = glm::inverse(parentState.getTransform() * glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getOriginalRotation())); + state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation())); glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAtDelta = lookAt; glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f)); @@ -836,6 +836,6 @@ void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; float angle = glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE); glm::quat rot = glm::angleAxis(angle, glm::axis(between)); - setJointRotationInConstrainedFrame(index, rot * state.getOriginalRotation(), DEFAULT_PRIORITY); + setJointRotationInConstrainedFrame(index, rot * state.getDefaultRotation(), DEFAULT_PRIORITY); } } From 145b730f80d4f52eba5861b53d37d0dcf825f463 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 7 Aug 2015 12:27:26 -0700 Subject: [PATCH 3/3] Clean up instantiation. --- libraries/animation/src/JointState.cpp | 114 ++++++++----------------- libraries/animation/src/JointState.h | 36 ++++---- libraries/animation/src/Rig.cpp | 6 +- libraries/render-utils/src/Model.cpp | 4 +- tests/animation/src/RigTests.cpp | 61 +++++++------ 5 files changed, 85 insertions(+), 136 deletions(-) diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index c81aae468d..440a1c18b3 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -18,16 +18,14 @@ #include "JointState.h" -JointState::JointState() : - _animationPriority(0.0f), - _transformChanged(true), - _rotationIsValid(false), - _positionInParentFrame(0.0f), - _distanceToParent(0.0f), - _constraint(NULL) { +JointState::~JointState() { + if (_constraint) { + delete _constraint; + _constraint = NULL; + } } -JointState::JointState(const JointState& other) : _constraint(NULL) { +void JointState::copyState(const JointState& other) { _transformChanged = other._transformChanged; _transform = other._transform; _rotationIsValid = other._rotationIsValid; @@ -36,14 +34,18 @@ JointState::JointState(const JointState& other) : _constraint(NULL) { _positionInParentFrame = other._positionInParentFrame; _distanceToParent = other._distanceToParent; _animationPriority = other._animationPriority; + + _visibleTransform = other._visibleTransform; + _visibleRotation = extractRotation(_visibleTransform); + _visibleRotationInConstrainedFrame = other._visibleRotationInConstrainedFrame; // DO NOT copy _constraint _name = other._name; _isFree = other._isFree; _boneRadius = other._boneRadius; _parentIndex = other._parentIndex; - _translation = other._translation; _defaultRotation = other._defaultRotation; _inverseDefaultRotation = other._inverseDefaultRotation; + _translation = other._translation; _rotationMin = other._rotationMin; _rotationMax = other._rotationMax; _preRotation = other._preRotation; @@ -52,49 +54,22 @@ JointState::JointState(const JointState& other) : _constraint(NULL) { _postTransform = other._postTransform; _inverseBindRotation = other._inverseBindRotation; } - -JointState::~JointState() { - delete _constraint; - _constraint = NULL; - if (_constraint) { - delete _constraint; - _constraint = NULL; - } -} - -glm::quat JointState::getRotation() const { - if (!_rotationIsValid) { - const_cast(this)->_rotation = extractRotation(_transform); - const_cast(this)->_rotationIsValid = true; - } - - return _rotation; -} - -void JointState::setFBXJoint(const FBXJoint* joint) { - assert(joint != NULL); - _rotationInConstrainedFrame = joint->rotation; - _transformChanged = true; - _rotationIsValid = false; - - _name = joint->name; - _isFree = joint->isFree; - _boneRadius = joint->boneRadius; - _parentIndex = joint->parentIndex; - _translation = joint->translation; - _defaultRotation = joint->rotation; - _inverseDefaultRotation = joint->inverseDefaultRotation; - _rotationMin = joint->rotationMin; - _rotationMax = joint->rotationMax; - _preRotation = joint->preRotation; - _postRotation = joint->postRotation; - _preTransform = joint->preTransform; - _postTransform = joint->postTransform; - _inverseBindRotation = joint->inverseBindRotation; - if (_constraint) { - delete _constraint; - _constraint = NULL; - } +JointState::JointState(const FBXJoint& joint) { + _rotationInConstrainedFrame = joint.rotation; + _name = joint.name; + _isFree = joint.isFree; + _boneRadius = joint.boneRadius; + _parentIndex = joint.parentIndex; + _translation = joint.translation; + _defaultRotation = joint.rotation; + _inverseDefaultRotation = joint.inverseDefaultRotation; + _rotationMin = joint.rotationMin; + _rotationMax = joint.rotationMax; + _preRotation = joint.preRotation; + _postRotation = joint.postRotation; + _preTransform = joint.preTransform; + _postTransform = joint.postTransform; + _inverseBindRotation = joint.inverseBindRotation; } void JointState::buildConstraint() { @@ -109,34 +84,13 @@ void JointState::buildConstraint() { } } -void JointState::copyState(const JointState& state) { - _animationPriority = state._animationPriority; - _transformChanged = state._transformChanged; - _transform = state._transform; - _rotationIsValid = state._rotationIsValid; - _rotation = state._rotation; - _rotationInConstrainedFrame = state._rotationInConstrainedFrame; - _positionInParentFrame = state._positionInParentFrame; - _distanceToParent = state._distanceToParent; - - _visibleTransform = state._visibleTransform; - _visibleRotation = extractRotation(_visibleTransform); - _visibleRotationInConstrainedFrame = state._visibleRotationInConstrainedFrame; - // DO NOT copy _constraint - _name = state._name; - _isFree = state._isFree; - _boneRadius = state._boneRadius; - _parentIndex = state._parentIndex; - _defaultRotation = state._defaultRotation; - _inverseDefaultRotation = state._inverseDefaultRotation; - _translation = state._translation; - _rotationMin = state._rotationMin; - _rotationMax = state._rotationMax; - _preRotation = state._preRotation; - _postRotation = state._postRotation; - _preTransform = state._preTransform; - _postTransform = state._postTransform; - _inverseBindRotation = state._inverseBindRotation; +glm::quat JointState::getRotation() const { + if (!_rotationIsValid) { + const_cast(this)->_rotation = extractRotation(_transform); + const_cast(this)->_rotationIsValid = true; + } + + return _rotation; } void JointState::initTransform(const glm::mat4& parentTransform) { diff --git a/libraries/animation/src/JointState.h b/libraries/animation/src/JointState.h index 51f92f3ace..694700338d 100644 --- a/libraries/animation/src/JointState.h +++ b/libraries/animation/src/JointState.h @@ -26,15 +26,13 @@ class AngularConstraint; class JointState { public: - JointState(); - JointState(const JointState& other); + JointState() {} + JointState(const JointState& other) : _constraint(NULL) { copyState(other); } + JointState(const FBXJoint& joint); ~JointState(); - - void setFBXJoint(const FBXJoint* joint); - - void buildConstraint(); void copyState(const JointState& state); - + void buildConstraint(); + void initTransform(const glm::mat4& parentTransform); // if synchronousRotationCompute is true, then _transform is still computed synchronously, // but _rotation will be asynchronously extracted @@ -98,9 +96,7 @@ public: void slaveVisibleTransform(); - float _animationPriority; // the priority of the animation affecting this joint - - /// \return parent model-frame rotation + /// \return parent model-frame rotation // (used to keep _rotation consistent when modifying _rotationInWorldFrame directly) glm::quat computeParentRotation() const; glm::quat computeVisibleParentRotation() const; @@ -118,19 +114,24 @@ public: const QString& getName() const { return _name; } float getBoneRadius() const { return _boneRadius; } bool getIsFree() const { return _isFree; } + float getAnimationPriority() const { return _animationPriority; } + void setAnimationPriority(float priority) { _animationPriority = priority; } private: void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation); /// debug helper function void loadBindRotation(); - bool _transformChanged; + bool _transformChanged {true}; + bool _rotationIsValid {false}; + glm::vec3 _positionInParentFrame {0.0f}; // only changes when the Model is scaled + float _animationPriority {0.0f}; // the priority of the animation affecting this joint + float _distanceToParent {0.0f}; + AngularConstraint* _constraint{nullptr}; // JointState owns its AngularConstraint + glm::mat4 _transform; // joint- to model-frame - bool _rotationIsValid; glm::quat _rotation; // joint- to model-frame glm::quat _rotationInConstrainedFrame; // rotation in frame where angular constraints would be applied - glm::vec3 _positionInParentFrame; // only changes when the Model is scaled - float _distanceToParent; glm::mat4 _visibleTransform; glm::quat _visibleRotation; @@ -139,8 +140,10 @@ private: glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform glm::quat _inverseDefaultRotation; glm::vec3 _translation; - float _boneRadius; + QString _name; + int _parentIndex; bool _isFree; + float _boneRadius; glm::vec3 _rotationMin; glm::vec3 _rotationMax; glm::quat _preRotation; @@ -148,9 +151,6 @@ private: glm::mat4 _preTransform; glm::mat4 _postTransform; glm::quat _inverseBindRotation; - int _parentIndex; - QString _name; - AngularConstraint* _constraint; // JointState owns its AngularConstraint }; #endif // hifi_JointState_h diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 207cb5e4e1..8b6c768bbd 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -299,20 +299,20 @@ void Rig::clearJointStates() { void Rig::clearJointAnimationPriority(int index) { if (index != -1 && index < _jointStates.size()) { - _jointStates[index]._animationPriority = 0.0f; + _jointStates[index].setAnimationPriority(0.0f); } } float Rig::getJointAnimatinoPriority(int index) { if (index != -1 && index < _jointStates.size()) { - return _jointStates[index]._animationPriority; + return _jointStates[index].getAnimationPriority(); } return 0.0f; } void Rig::setJointAnimatinoPriority(int index, float newPriority) { if (index != -1 && index < _jointStates.size()) { - _jointStates[index]._animationPriority = newPriority; + _jointStates[index].setAnimationPriority(newPriority); } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index cf0fb67d8c..5aa89c4cf7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -226,9 +226,7 @@ QVector Model::createJointStates(const FBXGeometry& geometry) { for (int i = 0; i < geometry.joints.size(); ++i) { const FBXJoint& joint = geometry.joints[i]; // store a pointer to the FBXJoint in the JointState - JointState state; - state.setFBXJoint(&joint); - + JointState state(joint); jointStates.append(state); } return jointStates; diff --git a/tests/animation/src/RigTests.cpp b/tests/animation/src/RigTests.cpp index 79c2f3b5df..b0e0a53ee5 100644 --- a/tests/animation/src/RigTests.cpp +++ b/tests/animation/src/RigTests.cpp @@ -47,39 +47,9 @@ #include "AvatarRig.h" // We might later test Rig vs AvatarRig separately, but for now, we're concentrating on the main use case. #include "RigTests.h" -QTEST_MAIN(RigTests) - -void RigTests::initTestCase() { -//#define FROM_FILE "/Users/howardstearns/howardHiFi/Zack.fbx" -#ifdef FROM_FILE - QFile file(FROM_FILE); - QCOMPARE(file.open(QIODevice::ReadOnly), true); - FBXGeometry geometry = readFBX(file.readAll(), QVariantHash()); -#else - QUrl fbxUrl("https://s3.amazonaws.com/hifi-public/models/skeletons/Zack/Zack.fbx"); - QNetworkReply* reply = OBJReader().request(fbxUrl, false); // Just a convenience hack for synchronoud http request - auto fbxHttpCode = !reply->isFinished() ? -1 : reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - QCOMPARE(fbxHttpCode, 200); - FBXGeometry geometry = readFBX(reply->readAll(), QVariantHash()); -#endif - - QVector jointStates; - for (int i = 0; i < geometry.joints.size(); ++i) { - // Note that if the geometry is stack allocated and goes away, so will the joints. Hence the heap copy here. - FBXJoint* joint = new FBXJoint(geometry.joints[i]); - JointState state; - state.setFBXJoint(joint); - jointStates.append(state); - } - - _rig = std::make_shared(); - _rig->initJointStates(jointStates, glm::mat4()); - std::cout << "Rig is ready " << geometry.joints.count() << " joints " << std::endl; - } - static void reportJoint(int index, JointState joint) { // Handy for debugging std::cout << "\n"; - std::cout << index << " " << joint.getName.toUtf8().data() << "\n"; + std::cout << index << " " << joint.getName().toUtf8().data() << "\n"; std::cout << " pos:" << joint.getPosition() << "/" << joint.getPositionInParentFrame() << " from " << joint.getParentIndex() << "\n"; std::cout << " rot:" << safeEulerAngles(joint.getRotation()) << "/" << safeEulerAngles(joint.getRotationInParentFrame()) << "/" << safeEulerAngles(joint.getRotationInBindFrame()) << "\n"; std::cout << "\n"; @@ -101,7 +71,34 @@ static void reportSome(RigPointer rig) { } } +QTEST_MAIN(RigTests) + +void RigTests::initTestCase() { +//#define FROM_FILE "/Users/howardstearns/howardHiFi/Zack.fbx" +#ifdef FROM_FILE + QFile file(FROM_FILE); + QCOMPARE(file.open(QIODevice::ReadOnly), true); + FBXGeometry geometry = readFBX(file.readAll(), QVariantHash()); +#else + QUrl fbxUrl("https://s3.amazonaws.com/hifi-public/models/skeletons/Zack/Zack.fbx"); + QNetworkReply* reply = OBJReader().request(fbxUrl, false); // Just a convenience hack for synchronoud http request + auto fbxHttpCode = !reply->isFinished() ? -1 : reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + QCOMPARE(fbxHttpCode, 200); + FBXGeometry geometry = readFBX(reply->readAll(), QVariantHash()); +#endif + + QVector jointStates; + for (int i = 0; i < geometry.joints.size(); ++i) { + JointState state(geometry.joints[i]); + jointStates.append(state); + } + + _rig = std::make_shared(); + _rig->initJointStates(jointStates, glm::mat4(), 0, 41, 40, 39, 17, 16, 15); // FIXME? get by name? do we really want to exclude the shoulder blades? + std::cout << "Rig is ready " << geometry.joints.count() << " joints " << std::endl; + reportAll(_rig); + } + void RigTests::initialPoseArmsDown() { - //reportAll(_rig); reportSome(_rig); }