From c2e4a70685c154b1dbf0cf7ffb2105fa8edb0e09 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 13 Nov 2013 10:35:20 -0800 Subject: [PATCH] Back to the cyclic coordinate descent algorithm (easier to apply joint constraints); Leap hands relative to eyes. --- interface/src/avatar/Avatar.cpp | 9 ++-- interface/src/avatar/Hand.cpp | 2 +- interface/src/renderer/Model.cpp | 81 ++++++++++++-------------------- 3 files changed, 36 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 929b5b600b..0f07e3a0ff 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -665,14 +665,15 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ float distance = glm::length(armVector); // don't let right hand get dragged beyond maximum arm length... + float armLength = _skeletonModel.isActive() ? _skeletonModel.getRightArmLength() : _skeleton.getArmLength(); const float ARM_RETRACTION = 0.75f; - float armLength = _maxArmLength * ARM_RETRACTION; - if (distance > armLength) { + float retractedArmLength = armLength * ARM_RETRACTION; + if (distance > retractedArmLength) { // reset right hand to be constrained to maximum arm length fingerJoint.position = shoulderJoint.position; glm::vec3 armNormal = armVector / distance; - armVector = armNormal * armLength; - distance = armLength; + armVector = armNormal * retractedArmLength; + distance = retractedArmLength; glm::vec3 constrainedPosition = shoulderJoint.position; constrainedPosition += armVector; fingerJoint.position = constrainedPosition; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index a9397913bb..d1d952e0c8 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -66,7 +66,7 @@ void Hand::calculateGeometry() { const glm::vec3 leapHandsOffsetFromFace(0.0, -0.2, -0.3); // place the hand in front of the face where we can see it Head& head = _owningAvatar->getHead(); - _basePosition = head.getPosition() + head.getOrientation() * leapHandsOffsetFromFace; + _basePosition = head.calculateAverageEyePosition() + head.getOrientation() * leapHandsOffsetFromFace * head.getScale(); _baseOrientation = head.getOrientation(); // generate finger tip balls.... diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a5c4a1e9c5..ca555adaba 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -594,58 +594,36 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } - - // this is a constraint relaxation algorithm: see - // http://www.ryanjuckett.com/programming/animation/22-constraint-relaxation-ik-in-2d - - // the influence of gravity; lowers the potential energy of our configurations - glm::vec3 gravity = _rotation * IDENTITY_UP * -0.01f; - - // over one or more iterations, apply the length constraints and update the rotations accordingly - float uniformScale = (_scale.x + _scale.y + _scale.z) / 3.0f; - const int ITERATION_COUNT = 3; - for (int i = 0; i < ITERATION_COUNT; i++) { - // start by optimistically setting the position of the end joint to our target - setJointTranslation(jointIndex, freeLineage.at(1), -1, relativePosition); - - for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { - int sourceIndex = freeLineage.at(j); - int destIndex = freeLineage.at(j - 1); - JointState& sourceState = _jointStates[sourceIndex]; - JointState& destState = _jointStates[destIndex]; - glm::vec3 sourceTranslation = extractTranslation(sourceState.transform); - glm::vec3 destTranslation = extractTranslation(destState.transform); - glm::vec3 boneVector = destTranslation - sourceTranslation; - float boneLength = glm::length(boneVector); - if (boneLength < EPSILON) { - continue; - } - float extension = geometry.joints.at(destIndex).distanceToParent * uniformScale / boneLength - 1.0f; - if (fabs(extension) < EPSILON) { - continue; - } - if (j == 1) { - setJointTranslation(sourceIndex, freeLineage.at(j + 1), -1, - sourceTranslation - boneVector * extension + gravity); - - } else if (sourceIndex == lastFreeIndex) { - setJointTranslation(destIndex, -1, freeLineage.at(j - 2), - destTranslation + boneVector * extension + gravity); - } else { - setJointTranslation(sourceIndex, freeLineage.at(j + 1), -1, - sourceTranslation - boneVector * extension * 0.5f + gravity); - setJointTranslation(destIndex, -1, freeLineage.at(j - 2), - destTranslation + boneVector * extension * 0.5f + gravity); + // this is a cyclic coordinate descent algorithm: see + // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d + const int ITERATION_COUNT = 1; + for (int i = 0; i < ITERATION_COUNT; i++) { + // first, we go from the joint upwards, rotating the end as close as possible to the target + glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform); + for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { + int index = freeLineage.at(j); + if (glm::distance(endPosition, relativePosition) < EPSILON) { + return true; // close enough to target position } - } - - // now update the joint states from the top - for (int j = freeLineage.size() - 1; j >= 0; j--) { - updateJointState(freeLineage.at(j)); - } + const FBXJoint& joint = geometry.joints.at(index); + if (!joint.isFree) { + continue; + } + JointState& state = _jointStates[index]; + glm::vec3 jointPosition = extractTranslation(state.transform); + glm::vec3 jointVector = endPosition - jointPosition; + glm::quat oldCombinedRotation = state.combinedRotation; + applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); + endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + } } - + + // now update the joint states from the top + for (int j = freeLineage.size() - 1; j >= 0; j--) { + updateJointState(freeLineage.at(j)); + } + return true; } @@ -679,9 +657,10 @@ float Model::getLimbLength(int jointIndex) const { } const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; - int length = 0.0f; + float length = 0.0f; + float lengthScale = (_scale.x + _scale.y + _scale.z) / 3.0f; for (int i = freeLineage.size() - 2; i >= 0; i--) { - length += geometry.joints.at(freeLineage.at(i)).distanceToParent; + length += geometry.joints.at(freeLineage.at(i)).distanceToParent * lengthScale; } return length; }