From c7e4bf931b49e3dd04c8f4595572e8395efe1850 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Tue, 27 Jun 2017 19:23:59 -0700
Subject: [PATCH 01/12] WIP: first steps toward smoothing ik chains

---
 .../animation/src/AnimInverseKinematics.cpp   | 109 +++++++++++-------
 .../animation/src/AnimInverseKinematics.h     |   8 +-
 libraries/animation/src/AnimSkeleton.cpp      |  14 +++
 libraries/animation/src/AnimSkeleton.h        |   1 +
 4 files changed, 85 insertions(+), 47 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index d7076a443e..4ec10b9faf 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -23,18 +23,18 @@
 #include "CubicHermiteSpline.h"
 #include "AnimUtil.h"
 
-static void lookupJointChainInfo(AnimInverseKinematics::JointChainInfo* jointChainInfos, size_t numJointChainInfos,
+static void lookupJointChainInfo(const std::vector<AnimInverseKinematics::JointChainInfo>& jointChainInfoVec,
                                  int indexA, int indexB,
-                                 AnimInverseKinematics::JointChainInfo** jointChainInfoA,
-                                 AnimInverseKinematics::JointChainInfo** jointChainInfoB) {
+                                 const AnimInverseKinematics::JointChainInfo** jointChainInfoA,
+                                 const AnimInverseKinematics::JointChainInfo** jointChainInfoB) {
     *jointChainInfoA = nullptr;
     *jointChainInfoB = nullptr;
-    for (size_t i = 0; i < numJointChainInfos; i++) {
-        if (jointChainInfos[i].jointIndex == indexA) {
-            *jointChainInfoA = jointChainInfos + i;
+    for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
+        if (jointChainInfoVec[i].jointIndex == indexA) {
+            *jointChainInfoA = &jointChainInfoVec[i];
         }
-        if (jointChainInfos[i].jointIndex == indexB) {
-            *jointChainInfoB = jointChainInfos + i;
+        if (jointChainInfoVec[i].jointIndex == indexB) {
+            *jointChainInfoB = &jointChainInfoVec[i];
         }
         if (*jointChainInfoA && *jointChainInfoB) {
             break;
@@ -234,6 +234,17 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         accumulator.clearAndClean();
     }
 
+    // initialize jointChainInfoVecVec, this holds the results for one iteration of each ik chain.
+    JointChainInfo defaultJointChainInfo = { glm::quat(), glm::vec3(), 0.0f, -1, false };
+    std::vector<std::vector<JointChainInfo>> jointChainInfoVecVec(targets.size());
+    for (size_t i = 0; i < targets.size(); i++) {
+        int chainDepth = _skeleton->getChainDepth(targets[i].getIndex());
+        jointChainInfoVecVec[i].reserve(chainDepth);
+        for (size_t j = 0; j < chainDepth; j++) {
+            jointChainInfoVecVec[i].push_back(defaultJointChainInfo);
+        }
+    }
+
     float maxError = FLT_MAX;
     int numLoops = 0;
     const int MAX_IK_LOOPS = 16;
@@ -244,11 +255,25 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         bool debug = context.getEnableDebugDrawIKChains() && numLoops == MAX_IK_LOOPS;
 
         // solve all targets
-        for (auto& target: targets) {
-            if (target.getType() == IKTarget::Type::Spline) {
-                solveTargetWithSpline(context, target, absolutePoses, debug);
+        for (size_t i = 0; i < targets.size(); i++) {
+            if (targets[i].getType() == IKTarget::Type::Spline) {
+                solveTargetWithSpline(context, targets[i], absolutePoses, debug, jointChainInfoVecVec[i]);
             } else {
-                solveTargetWithCCD(context, target, absolutePoses, debug);
+                solveTargetWithCCD(context, targets[i], absolutePoses, debug, jointChainInfoVecVec[i]);
+            }
+        }
+
+        // TODO: do smooth interpolation of joint chains here, if necessary.
+
+        // copy jointChainInfoVecs into accumulators
+        for (size_t i = 0; i < targets.size(); i++) {
+            const std::vector<JointChainInfo>& jointChainInfoVec = jointChainInfoVecVec[i];
+            for (size_t j = 0; j < jointChainInfoVec.size(); j++) {
+                const JointChainInfo& info = jointChainInfoVec[j];
+                if (info.jointIndex >= 0) {
+                    _rotationAccumulators[info.jointIndex].add(info.relRot, info.weight);
+                    _translationAccumulators[info.jointIndex].add(info.relTrans, info.weight);
+                }
             }
         }
 
@@ -310,7 +335,8 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
     }
 }
 
-void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug) {
+void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
+                                               bool debug, std::vector<JointChainInfo>& jointChainInfoVec) const {
     size_t chainDepth = 0;
 
     IKTarget::Type targetType = target.getType();
@@ -338,9 +364,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
     // the tip's parent-relative as we proceed up the chain
     glm::quat tipParentOrientation = absolutePoses[pivotIndex].rot();
 
-    const size_t MAX_CHAIN_DEPTH = 30;
-    JointChainInfo jointChainInfos[MAX_CHAIN_DEPTH];
-
     // NOTE: if this code is removed, the head will remain rigid, causing the spine/hips to thrust forward backward
     // as the head is nodded.
     if (targetType == IKTarget::Type::HmdHead ||
@@ -368,7 +391,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
         }
 
         glm::vec3 tipRelativeTranslation = _relativePoses[target.getIndex()].trans();
-        jointChainInfos[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, target.getWeight(), tipIndex, constrained };
+        jointChainInfoVec[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, target.getWeight(), tipIndex, constrained };
     }
 
     // cache tip absolute position
@@ -379,7 +402,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
     // descend toward root, pivoting each joint to get tip closer to target position
     while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
 
-        assert(chainDepth < MAX_CHAIN_DEPTH);
+        assert(chainDepth < jointChainInfoVec.size());
 
         // compute the two lines that should be aligned
         glm::vec3 jointPosition = absolutePoses[pivotIndex].trans();
@@ -480,7 +503,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
         }
 
         glm::vec3 newTrans = _relativePoses[pivotIndex].trans();
-        jointChainInfos[chainDepth] = { newRot, newTrans, target.getWeight(), pivotIndex, constrained };
+        jointChainInfoVec[chainDepth] = { newRot, newTrans, target.getWeight(), pivotIndex, constrained };
 
         // keep track of tip's new transform as we descend towards root
         tipPosition = jointPosition + deltaRotation * (tipPosition - jointPosition);
@@ -502,24 +525,25 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
                 int baseParentJointIndex = _skeleton->getParentIndex(baseJointIndex);
                 AnimPose topPose, midPose, basePose;
                 int topChainIndex = -1, baseChainIndex = -1;
+                const size_t MAX_CHAIN_DEPTH = 30;
                 AnimPose postAbsPoses[MAX_CHAIN_DEPTH];
                 AnimPose accum = absolutePoses[_hipsIndex];
                 AnimPose baseParentPose = absolutePoses[_hipsIndex];
                 for (int i = (int)chainDepth - 1; i >= 0; i--) {
-                    accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfos[i].relRot, jointChainInfos[i].relTrans);
+                    accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfoVec[i].relRot, jointChainInfoVec[i].relTrans);
                     postAbsPoses[i] = accum;
-                    if (jointChainInfos[i].jointIndex == topJointIndex) {
+                    if (jointChainInfoVec[i].jointIndex == topJointIndex) {
                         topChainIndex = i;
                         topPose = accum;
                     }
-                    if (jointChainInfos[i].jointIndex == midJointIndex) {
+                    if (jointChainInfoVec[i].jointIndex == midJointIndex) {
                         midPose = accum;
                     }
-                    if (jointChainInfos[i].jointIndex == baseJointIndex) {
+                    if (jointChainInfoVec[i].jointIndex == baseJointIndex) {
                         baseChainIndex = i;
                         basePose = accum;
                     }
-                    if (jointChainInfos[i].jointIndex == baseParentJointIndex) {
+                    if (jointChainInfoVec[i].jointIndex == baseParentJointIndex) {
                         baseParentPose = accum;
                     }
                 }
@@ -599,21 +623,16 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
                 }
 
                 glm::quat newBaseRelRot = glm::inverse(baseParentPose.rot()) * poleRot * basePose.rot();
-                jointChainInfos[baseChainIndex].relRot = newBaseRelRot;
+                jointChainInfoVec[baseChainIndex].relRot = newBaseRelRot;
 
                 glm::quat newTopRelRot = glm::inverse(midPose.rot()) * glm::inverse(poleRot) * topPose.rot();
-                jointChainInfos[topChainIndex].relRot = newTopRelRot;
+                jointChainInfoVec[topChainIndex].relRot = newTopRelRot;
             }
         }
     }
 
-    for (size_t i = 0; i < chainDepth; i++) {
-        _rotationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relRot, jointChainInfos[i].weight);
-        _translationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relTrans, jointChainInfos[i].weight);
-    }
-
     if (debug) {
-        debugDrawIKChain(jointChainInfos, chainDepth, context);
+        debugDrawIKChain(jointChainInfoVec, context);
     }
 }
 
@@ -697,10 +716,9 @@ const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics
     return nullptr;
 }
 
-void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug) {
-
-    const size_t MAX_CHAIN_DEPTH = 30;
-    JointChainInfo jointChainInfos[MAX_CHAIN_DEPTH];
+// AJT: TODO: make this const someday
+void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
+                                                  bool debug, std::vector<JointChainInfo>& jointChainInfoVec) {
 
     const int baseIndex = _hipsIndex;
 
@@ -783,19 +801,22 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
                 }
             }
 
-            jointChainInfos[i] = { relPose.rot(), relPose.trans(), target.getWeight(), splineJointInfo.jointIndex, constrained };
+            jointChainInfoVec[i] = { relPose.rot(), relPose.trans(), target.getWeight(), splineJointInfo.jointIndex, constrained };
 
             parentAbsPose = flexedAbsPose;
         }
     }
 
+    // AJT: REMOVE
+    /*
     for (size_t i = 0; i < splineJointInfoVec->size(); i++) {
         _rotationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relRot, jointChainInfos[i].weight);
         _translationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relTrans, jointChainInfos[i].weight);
     }
+    */
 
     if (debug) {
-        debugDrawIKChain(jointChainInfos, splineJointInfoVec->size(), context);
+        debugDrawIKChain(jointChainInfoVec, context);
     }
 }
 
@@ -1495,12 +1516,12 @@ void AnimInverseKinematics::debugDrawRelativePoses(const AnimContext& context) c
     }
 }
 
-void AnimInverseKinematics::debugDrawIKChain(JointChainInfo* jointChainInfos, size_t numJointChainInfos, const AnimContext& context) const {
+void AnimInverseKinematics::debugDrawIKChain(const std::vector<JointChainInfo>& jointChainInfoVec, const AnimContext& context) const {
     AnimPoseVec poses = _relativePoses;
 
     // copy debug joint rotations into the relative poses
-    for (size_t i = 0; i < numJointChainInfos; i++) {
-        const JointChainInfo& info = jointChainInfos[i];
+    for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
+        const JointChainInfo& info = jointChainInfoVec[i];
         poses[info.jointIndex].rot() = info.relRot;
         poses[info.jointIndex].trans() = info.relTrans;
     }
@@ -1519,9 +1540,9 @@ void AnimInverseKinematics::debugDrawIKChain(JointChainInfo* jointChainInfos, si
     // draw each pose
     for (int i = 0; i < (int)poses.size(); i++) {
         int parentIndex = _skeleton->getParentIndex(i);
-        JointChainInfo* jointInfo = nullptr;
-        JointChainInfo* parentJointInfo = nullptr;
-        lookupJointChainInfo(jointChainInfos, numJointChainInfos, i, parentIndex, &jointInfo, &parentJointInfo);
+        const JointChainInfo* jointInfo = nullptr;
+        const JointChainInfo* parentJointInfo = nullptr;
+        lookupJointChainInfo(jointChainInfoVec, i, parentIndex, &jointInfo, &parentJointInfo);
         if (jointInfo && parentJointInfo) {
 
             // transform local axes into world space.
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index d473ae3698..152034b596 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -73,10 +73,12 @@ public:
 protected:
     void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
     void solve(const AnimContext& context, const std::vector<IKTarget>& targets);
-    void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug);
-    void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug);
+    void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
+                            bool debug, std::vector<JointChainInfo>& jointChainInfoVec) const;
+    void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
+                               bool debug, std::vector<JointChainInfo>& jointChainInfoVec);
     virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
-    void debugDrawIKChain(JointChainInfo* jointChainInfos, size_t numJointChainInfos, const AnimContext& context) const;
+    void debugDrawIKChain(const std::vector<JointChainInfo>& jointChainInfoVec, const AnimContext& context) const;
     void debugDrawRelativePoses(const AnimContext& context) const;
     void debugDrawConstraints(const AnimContext& context) const;
     void debugDrawSpineSplines(const AnimContext& context, const std::vector<IKTarget>& targets) const;
diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp
index 062e016660..804ffb0583 100644
--- a/libraries/animation/src/AnimSkeleton.cpp
+++ b/libraries/animation/src/AnimSkeleton.cpp
@@ -42,6 +42,20 @@ int AnimSkeleton::getNumJoints() const {
     return _jointsSize;
 }
 
+int AnimSkeleton::getChainDepth(int jointIndex) const {
+    if (jointIndex >= 0) {
+        int chainDepth = 0;
+        int index = jointIndex;
+        do {
+            chainDepth++;
+            index = _joints[index].parentIndex;
+        } while (index != -1);
+        return chainDepth;
+    } else {
+        return 0;
+    }
+}
+
 const AnimPose& AnimSkeleton::getAbsoluteBindPose(int jointIndex) const {
     return _absoluteBindPoses[jointIndex];
 }
diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h
index 6315f2d62b..99c9a148f7 100644
--- a/libraries/animation/src/AnimSkeleton.h
+++ b/libraries/animation/src/AnimSkeleton.h
@@ -28,6 +28,7 @@ public:
     int nameToJointIndex(const QString& jointName) const;
     const QString& getJointName(int jointIndex) const;
     int getNumJoints() const;
+    int getChainDepth(int jointIndex) const;
 
     // absolute pose, not relative to parent
     const AnimPose& getAbsoluteBindPose(int jointIndex) const;

From 75e1a4a1e6f389da13861b2b2854f6e0e948efb4 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Wed, 28 Jun 2017 13:31:15 -0700
Subject: [PATCH 02/12] Refactor of JointChainInfo data structure

---
 .../animation/src/AnimInverseKinematics.cpp   | 103 +++++++++---------
 .../animation/src/AnimInverseKinematics.h     |  20 ++--
 2 files changed, 62 insertions(+), 61 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index 4ec10b9faf..ea87fab4c0 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -23,20 +23,21 @@
 #include "CubicHermiteSpline.h"
 #include "AnimUtil.h"
 
-static void lookupJointChainInfo(const std::vector<AnimInverseKinematics::JointChainInfo>& jointChainInfoVec,
+static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo,
                                  int indexA, int indexB,
-                                 const AnimInverseKinematics::JointChainInfo** jointChainInfoA,
-                                 const AnimInverseKinematics::JointChainInfo** jointChainInfoB) {
-    *jointChainInfoA = nullptr;
-    *jointChainInfoB = nullptr;
-    for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
-        if (jointChainInfoVec[i].jointIndex == indexA) {
-            *jointChainInfoA = &jointChainInfoVec[i];
+                                 const AnimInverseKinematics::JointInfo** jointInfoA,
+                                 const AnimInverseKinematics::JointInfo** jointInfoB) {
+    *jointInfoA = nullptr;
+    *jointInfoB = nullptr;
+    for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
+        const AnimInverseKinematics::JointInfo* jointInfo = &jointChainInfo.jointInfoVec[i];
+        if (jointInfo->jointIndex == indexA) {
+            *jointInfoA = jointInfo;
         }
-        if (jointChainInfoVec[i].jointIndex == indexB) {
-            *jointChainInfoB = &jointChainInfoVec[i];
+        if (jointInfo->jointIndex == indexB) {
+            *jointInfoB = jointInfo;
         }
-        if (*jointChainInfoA && *jointChainInfoB) {
+        if (*jointInfoA && *jointInfoB) {
             break;
         }
     }
@@ -234,14 +235,15 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         accumulator.clearAndClean();
     }
 
-    // initialize jointChainInfoVecVec, this holds the results for one iteration of each ik chain.
-    JointChainInfo defaultJointChainInfo = { glm::quat(), glm::vec3(), 0.0f, -1, false };
-    std::vector<std::vector<JointChainInfo>> jointChainInfoVecVec(targets.size());
+    // initialize a new jointChainInfoVec, this will holds the results for solving each ik chain.
+    JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
+    JointChainInfoVec jointChainInfoVec(targets.size());
     for (size_t i = 0; i < targets.size(); i++) {
         int chainDepth = _skeleton->getChainDepth(targets[i].getIndex());
-        jointChainInfoVecVec[i].reserve(chainDepth);
+        jointChainInfoVec[i].jointInfoVec.reserve(chainDepth);
+        jointChainInfoVec[i].target = targets[i];
         for (size_t j = 0; j < chainDepth; j++) {
-            jointChainInfoVecVec[i].push_back(defaultJointChainInfo);
+            jointChainInfoVec[i].jointInfoVec.push_back(defaultJointInfo);
         }
     }
 
@@ -257,9 +259,9 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         // solve all targets
         for (size_t i = 0; i < targets.size(); i++) {
             if (targets[i].getType() == IKTarget::Type::Spline) {
-                solveTargetWithSpline(context, targets[i], absolutePoses, debug, jointChainInfoVecVec[i]);
+                solveTargetWithSpline(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
             } else {
-                solveTargetWithCCD(context, targets[i], absolutePoses, debug, jointChainInfoVecVec[i]);
+                solveTargetWithCCD(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
             }
         }
 
@@ -267,12 +269,13 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
 
         // copy jointChainInfoVecs into accumulators
         for (size_t i = 0; i < targets.size(); i++) {
-            const std::vector<JointChainInfo>& jointChainInfoVec = jointChainInfoVecVec[i];
-            for (size_t j = 0; j < jointChainInfoVec.size(); j++) {
-                const JointChainInfo& info = jointChainInfoVec[j];
+            const std::vector<JointInfo>& jointInfoVec = jointChainInfoVec[i].jointInfoVec;
+            float weight = jointChainInfoVec[i].target.getWeight();
+            for (size_t j = 0; j < jointInfoVec.size(); j++) {
+                const JointInfo& info = jointInfoVec[j];
                 if (info.jointIndex >= 0) {
-                    _rotationAccumulators[info.jointIndex].add(info.relRot, info.weight);
-                    _translationAccumulators[info.jointIndex].add(info.relTrans, info.weight);
+                    _rotationAccumulators[info.jointIndex].add(info.rot, weight);
+                    _translationAccumulators[info.jointIndex].add(info.trans, weight);
                 }
             }
         }
@@ -336,7 +339,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
 }
 
 void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                                               bool debug, std::vector<JointChainInfo>& jointChainInfoVec) const {
+                                               bool debug, JointChainInfo& jointChainInfoOut) const {
     size_t chainDepth = 0;
 
     IKTarget::Type targetType = target.getType();
@@ -391,7 +394,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
         }
 
         glm::vec3 tipRelativeTranslation = _relativePoses[target.getIndex()].trans();
-        jointChainInfoVec[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, target.getWeight(), tipIndex, constrained };
+        jointChainInfoOut.jointInfoVec[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, tipIndex, constrained };
     }
 
     // cache tip absolute position
@@ -402,7 +405,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
     // descend toward root, pivoting each joint to get tip closer to target position
     while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
 
-        assert(chainDepth < jointChainInfoVec.size());
+        assert(chainDepth < jointChainInfoOut.jointInfoVec.size());
 
         // compute the two lines that should be aligned
         glm::vec3 jointPosition = absolutePoses[pivotIndex].trans();
@@ -503,7 +506,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
         }
 
         glm::vec3 newTrans = _relativePoses[pivotIndex].trans();
-        jointChainInfoVec[chainDepth] = { newRot, newTrans, target.getWeight(), pivotIndex, constrained };
+        jointChainInfoOut.jointInfoVec[chainDepth] = { newRot, newTrans, pivotIndex, constrained };
 
         // keep track of tip's new transform as we descend towards root
         tipPosition = jointPosition + deltaRotation * (tipPosition - jointPosition);
@@ -530,20 +533,20 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
                 AnimPose accum = absolutePoses[_hipsIndex];
                 AnimPose baseParentPose = absolutePoses[_hipsIndex];
                 for (int i = (int)chainDepth - 1; i >= 0; i--) {
-                    accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfoVec[i].relRot, jointChainInfoVec[i].relTrans);
+                    accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfoOut.jointInfoVec[i].rot, jointChainInfoOut.jointInfoVec[i].trans);
                     postAbsPoses[i] = accum;
-                    if (jointChainInfoVec[i].jointIndex == topJointIndex) {
+                    if (jointChainInfoOut.jointInfoVec[i].jointIndex == topJointIndex) {
                         topChainIndex = i;
                         topPose = accum;
                     }
-                    if (jointChainInfoVec[i].jointIndex == midJointIndex) {
+                    if (jointChainInfoOut.jointInfoVec[i].jointIndex == midJointIndex) {
                         midPose = accum;
                     }
-                    if (jointChainInfoVec[i].jointIndex == baseJointIndex) {
+                    if (jointChainInfoOut.jointInfoVec[i].jointIndex == baseJointIndex) {
                         baseChainIndex = i;
                         basePose = accum;
                     }
-                    if (jointChainInfoVec[i].jointIndex == baseParentJointIndex) {
+                    if (jointChainInfoOut.jointInfoVec[i].jointIndex == baseParentJointIndex) {
                         baseParentPose = accum;
                     }
                 }
@@ -623,16 +626,16 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
                 }
 
                 glm::quat newBaseRelRot = glm::inverse(baseParentPose.rot()) * poleRot * basePose.rot();
-                jointChainInfoVec[baseChainIndex].relRot = newBaseRelRot;
+                jointChainInfoOut.jointInfoVec[baseChainIndex].rot = newBaseRelRot;
 
                 glm::quat newTopRelRot = glm::inverse(midPose.rot()) * glm::inverse(poleRot) * topPose.rot();
-                jointChainInfoVec[topChainIndex].relRot = newTopRelRot;
+                jointChainInfoOut.jointInfoVec[topChainIndex].rot = newTopRelRot;
             }
         }
     }
 
     if (debug) {
-        debugDrawIKChain(jointChainInfoVec, context);
+        debugDrawIKChain(jointChainInfoOut, context);
     }
 }
 
@@ -718,7 +721,7 @@ const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics
 
 // AJT: TODO: make this const someday
 void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                                                  bool debug, std::vector<JointChainInfo>& jointChainInfoVec) {
+                                                  bool debug, JointChainInfo& jointChainInfoOut) {
 
     const int baseIndex = _hipsIndex;
 
@@ -801,22 +804,14 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
                 }
             }
 
-            jointChainInfoVec[i] = { relPose.rot(), relPose.trans(), target.getWeight(), splineJointInfo.jointIndex, constrained };
+            jointChainInfoOut.jointInfoVec[i] = { relPose.rot(), relPose.trans(), splineJointInfo.jointIndex, constrained };
 
             parentAbsPose = flexedAbsPose;
         }
     }
 
-    // AJT: REMOVE
-    /*
-    for (size_t i = 0; i < splineJointInfoVec->size(); i++) {
-        _rotationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relRot, jointChainInfos[i].weight);
-        _translationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relTrans, jointChainInfos[i].weight);
-    }
-    */
-
     if (debug) {
-        debugDrawIKChain(jointChainInfoVec, context);
+        debugDrawIKChain(jointChainInfoOut, context);
     }
 }
 
@@ -1516,14 +1511,14 @@ void AnimInverseKinematics::debugDrawRelativePoses(const AnimContext& context) c
     }
 }
 
-void AnimInverseKinematics::debugDrawIKChain(const std::vector<JointChainInfo>& jointChainInfoVec, const AnimContext& context) const {
+void AnimInverseKinematics::debugDrawIKChain(const JointChainInfo& jointChainInfo, const AnimContext& context) const {
     AnimPoseVec poses = _relativePoses;
 
     // copy debug joint rotations into the relative poses
-    for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
-        const JointChainInfo& info = jointChainInfoVec[i];
-        poses[info.jointIndex].rot() = info.relRot;
-        poses[info.jointIndex].trans() = info.relTrans;
+    for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
+        const JointInfo& info = jointChainInfo.jointInfoVec[i];
+        poses[info.jointIndex].rot() = info.rot;
+        poses[info.jointIndex].trans() = info.trans;
     }
 
     // convert relative poses to absolute
@@ -1540,9 +1535,9 @@ void AnimInverseKinematics::debugDrawIKChain(const std::vector<JointChainInfo>&
     // draw each pose
     for (int i = 0; i < (int)poses.size(); i++) {
         int parentIndex = _skeleton->getParentIndex(i);
-        const JointChainInfo* jointInfo = nullptr;
-        const JointChainInfo* parentJointInfo = nullptr;
-        lookupJointChainInfo(jointChainInfoVec, i, parentIndex, &jointInfo, &parentJointInfo);
+        const JointInfo* jointInfo = nullptr;
+        const JointInfo* parentJointInfo = nullptr;
+        lookupJointInfo(jointChainInfo, i, parentIndex, &jointInfo, &parentJointInfo);
         if (jointInfo && parentJointInfo) {
 
             // transform local axes into world space.
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index 152034b596..38288aa288 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -26,14 +26,20 @@ class RotationConstraint;
 class AnimInverseKinematics : public AnimNode {
 public:
 
-    struct JointChainInfo {
-        glm::quat relRot;
-        glm::vec3 relTrans;
-        float weight;
+    struct JointInfo {
+        glm::quat rot;
+        glm::vec3 trans;
         int jointIndex;
         bool constrained;
     };
 
+    struct JointChainInfo {
+        std::vector<JointInfo> jointInfoVec;
+        IKTarget target;
+    };
+
+    using JointChainInfoVec = std::vector<JointChainInfo>;
+
     explicit AnimInverseKinematics(const QString& id);
     virtual ~AnimInverseKinematics() override;
 
@@ -74,11 +80,11 @@ protected:
     void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
     void solve(const AnimContext& context, const std::vector<IKTarget>& targets);
     void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                            bool debug, std::vector<JointChainInfo>& jointChainInfoVec) const;
+                            bool debug, JointChainInfo& jointChainInfoOut) const;
     void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                               bool debug, std::vector<JointChainInfo>& jointChainInfoVec);
+                               bool debug, JointChainInfo& jointChainInfoOut);
     virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
-    void debugDrawIKChain(const std::vector<JointChainInfo>& jointChainInfoVec, const AnimContext& context) const;
+    void debugDrawIKChain(const JointChainInfo& jointChainInfo, const AnimContext& context) const;
     void debugDrawRelativePoses(const AnimContext& context) const;
     void debugDrawConstraints(const AnimContext& context) const;
     void debugDrawSpineSplines(const AnimContext& context, const std::vector<IKTarget>& targets) const;

From 237872e4779ad9a6c0e3007e1b3e9dae3ca04c25 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 30 Jun 2017 12:47:01 -0700
Subject: [PATCH 03/12] sizes and order of IKTargetVarVec and IKTargetVec are
 now the same.

Also, A change in how the bone name to bone index lookup occurs exposed a bug
in Rig::computeAvatarBoundingCapsule(), basically it was not actually preforming IK,
and the ik targets were in the wrong coordinate frame.  So when IK was actually
performed it would give bad results.  This bug is now fixed.
---
 .../animation/src/AnimInverseKinematics.cpp   | 56 +++++++------------
 .../animation/src/AnimInverseKinematics.h     |  4 --
 libraries/animation/src/IKTarget.h            |  2 +-
 libraries/animation/src/Rig.cpp               | 18 +++---
 4 files changed, 32 insertions(+), 48 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index ea87fab4c0..5ea628d1f4 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -150,24 +150,26 @@ void AnimInverseKinematics::setTargetVars(const QString& jointName, const QStrin
 }
 
 void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses) {
-    // build a list of valid targets from _targetVarVec and animVars
-    _maxTargetIndex = -1;
+
     _hipsTargetIndex = -1;
-    bool removeUnfoundJoints = false;
+
+    targets.reserve(_targetVarVec.size());
 
     for (auto& targetVar : _targetVarVec) {
+
+        // update targetVar jointIndex cache
         if (targetVar.jointIndex == -1) {
-            // this targetVar hasn't been validated yet...
             int jointIndex = _skeleton->nameToJointIndex(targetVar.jointName);
             if (jointIndex >= 0) {
                 // this targetVar has a valid joint --> cache the indices
                 targetVar.jointIndex = jointIndex;
             } else {
                 qCWarning(animation) << "AnimInverseKinematics could not find jointName" << targetVar.jointName << "in skeleton";
-                removeUnfoundJoints = true;
             }
-        } else {
-            IKTarget target;
+        }
+
+        IKTarget target;
+        if (targetVar.jointIndex != -1) {
             target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
             if (target.getType() != IKTarget::Type::Unknown) {
                 AnimPose absPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
@@ -189,35 +191,16 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
                 glm::vec3 poleReferenceVector = animVars.lookupRigToGeometryVector(targetVar.poleReferenceVectorVar, Vectors::UNIT_Z);
                 target.setPoleReferenceVector(glm::normalize(poleReferenceVector));
 
-                targets.push_back(target);
-
-                if (targetVar.jointIndex > _maxTargetIndex) {
-                    _maxTargetIndex = targetVar.jointIndex;
-                }
-
                 // record the index of the hips ik target.
                 if (target.getIndex() == _hipsIndex) {
-                    _hipsTargetIndex = (int)targets.size() - 1;
+                    _hipsTargetIndex = (int)targets.size();
                 }
             }
+        } else {
+            target.setType((int)IKTarget::Type::Unknown);
         }
-    }
 
-    if (removeUnfoundJoints) {
-        int numVars = (int)_targetVarVec.size();
-        int i = 0;
-        while (i < numVars) {
-            if (_targetVarVec[i].jointIndex == -1) {
-                if (numVars > 1) {
-                    // swap i for last element
-                    _targetVarVec[i] = _targetVarVec[numVars - 1];
-                }
-                _targetVarVec.pop_back();
-                --numVars;
-            } else {
-                ++i;
-            }
-        }
+        targets.push_back(target);
     }
 }
 
@@ -258,10 +241,15 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
 
         // solve all targets
         for (size_t i = 0; i < targets.size(); i++) {
-            if (targets[i].getType() == IKTarget::Type::Spline) {
+            switch (targets[i].getType()) {
+            case IKTarget::Type::Unknown:
+                break;
+            case IKTarget::Type::Spline:
                 solveTargetWithSpline(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
-            } else {
+                break;
+            default:
                 solveTargetWithCCD(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
+                break;
             }
         }
 
@@ -317,7 +305,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
     // finally set the relative rotation of each tip to agree with absolute target rotation
     for (auto& target: targets) {
         int tipIndex = target.getIndex();
-        int parentIndex = _skeleton->getParentIndex(tipIndex);
+        int parentIndex = (tipIndex >= 0) ? _skeleton->getParentIndex(tipIndex) : -1;
 
         // update rotationOnly targets that don't lie on the ik chain of other ik targets.
         if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() && target.getType() == IKTarget::Type::RotationOnly) {
@@ -1430,8 +1418,6 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
         targetVar.jointIndex = -1;
     }
 
-    _maxTargetIndex = -1;
-
     for (auto& accumulator: _rotationAccumulators) {
         accumulator.clearAndClean();
     }
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index 38288aa288..fb462cbf50 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -156,10 +156,6 @@ protected:
     int _leftHandIndex { -1 };
     int _rightHandIndex { -1 };
 
-    // _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
-    // during the the cyclic coordinate descent algorithm
-    int _maxTargetIndex { 0 };
-
     float _maxErrorOnLastSolve { FLT_MAX };
     bool _previousEnableDebugIKTargets { false };
     SolutionSource _solutionSource { SolutionSource::RelaxToUnderPoses };
diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h
index 5567539659..a86ae0ca8b 100644
--- a/libraries/animation/src/IKTarget.h
+++ b/libraries/animation/src/IKTarget.h
@@ -57,7 +57,7 @@ private:
     bool _poleVectorEnabled { false };
     int _index { -1 };
     Type _type { Type::RotationAndPosition };
-    float _weight;
+    float _weight { 0.0f };
     float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
     size_t _numFlexCoefficients;
 };
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 3d04b0b26f..7b11465062 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1707,36 +1707,38 @@ void Rig::computeAvatarBoundingCapsule(
 
     AnimPose geometryToRig = _modelOffset * _geometryOffset;
 
-    AnimPose hips(glm::vec3(1), glm::quat(), glm::vec3());
+    glm::vec3 hipsPosition(0.0f);
     int hipsIndex = indexOfJoint("Hips");
     if (hipsIndex >= 0) {
-        hips = geometryToRig * _animSkeleton->getAbsoluteBindPose(hipsIndex);
+        hipsPosition = transformPoint(_geometryToRigTransform, _animSkeleton->getAbsoluteDefaultPose(hipsIndex).trans());
     }
     AnimVariantMap animVars;
+    animVars.setRigToGeometryTransform(_rigToGeometryTransform);
     glm::quat handRotation = glm::angleAxis(PI, Vectors::UNIT_X);
-    animVars.set("leftHandPosition", hips.trans());
+    animVars.set("leftHandPosition", hipsPosition);
     animVars.set("leftHandRotation", handRotation);
     animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
-    animVars.set("rightHandPosition", hips.trans());
+    animVars.set("rightHandPosition", hipsPosition);
     animVars.set("rightHandRotation", handRotation);
     animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
 
     int rightFootIndex = indexOfJoint("RightFoot");
     int leftFootIndex = indexOfJoint("LeftFoot");
     if (rightFootIndex != -1 && leftFootIndex != -1) {
-        glm::vec3 foot = Vectors::ZERO;
+        glm::vec3 geomFootPosition = glm::vec3(0.0f, _animSkeleton->getAbsoluteDefaultPose(rightFootIndex).trans().y, 0.0f);
+        glm::vec3 footPosition = transformPoint(_geometryToRigTransform, geomFootPosition);
         glm::quat footRotation = glm::angleAxis(0.5f * PI, Vectors::UNIT_X);
-        animVars.set("leftFootPosition", foot);
+        animVars.set("leftFootPosition", footPosition);
         animVars.set("leftFootRotation", footRotation);
         animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
-        animVars.set("rightFootPosition", foot);
+        animVars.set("rightFootPosition", footPosition);
         animVars.set("rightFootRotation", footRotation);
         animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
     }
 
     // call overlay twice: once to verify AnimPoseVec joints and again to do the IK
     AnimNode::Triggers triggersOut;
-    AnimContext context(false, false, false, glm::mat4(), glm::mat4());
+    AnimContext context(false, false, false, _geometryToRigTransform, _rigToGeometryTransform);
     float dt = 1.0f; // the value of this does not matter
     ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());
     AnimPoseVec finalPoses =  ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());

From aba164b26e2e08ad6ea1a9e48b55d509c183f27a Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 30 Jun 2017 13:27:53 -0700
Subject: [PATCH 04/12] more clean up of Rig::computeAvatarBoundingCapsule

---
 libraries/animation/src/Rig.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 7b11465062..0dfeb43f3d 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1704,9 +1704,6 @@ void Rig::computeAvatarBoundingCapsule(
     ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation",
                          "rightFootType", "rightFootWeight", 1.0f, {},
                          QString(), QString(), QString());
-
-    AnimPose geometryToRig = _modelOffset * _geometryOffset;
-
     glm::vec3 hipsPosition(0.0f);
     int hipsIndex = indexOfJoint("Hips");
     if (hipsIndex >= 0) {
@@ -1771,14 +1768,15 @@ void Rig::computeAvatarBoundingCapsule(
 
     // compute bounding shape parameters
     // NOTE: we assume that the longest side of totalExtents is the yAxis...
-    glm::vec3 diagonal = (geometryToRig * totalExtents.maximum) - (geometryToRig * totalExtents.minimum);
+    glm::vec3 diagonal = (transformPoint(_geometryToRigTransform, totalExtents.maximum) -
+                          transformPoint(_geometryToRigTransform, totalExtents.minimum));
     // ... and assume the radiusOut is half the RMS of the X and Z sides:
     radiusOut = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
     heightOut = diagonal.y - 2.0f * radiusOut;
 
     glm::vec3 rootPosition = finalPoses[geometry.rootJointIndex].trans();
-    glm::vec3 rigCenter = (geometryToRig * (0.5f * (totalExtents.maximum + totalExtents.minimum)));
-    localOffsetOut = rigCenter - (geometryToRig * rootPosition);
+    glm::vec3 rigCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum)));
+    localOffsetOut = rigCenter - transformPoint(_geometryToRigTransform, rootPosition);
 }
 
 bool Rig::transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,

From 2f6a37ee53fc5e1546a1592259d94d7d71d4ce21 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Mon, 3 Jul 2017 16:31:05 -0700
Subject: [PATCH 05/12] Removed interpolation of hand controllers

---
 libraries/animation/src/Rig.cpp | 79 +++------------------------------
 libraries/animation/src/Rig.h   |  9 ----
 2 files changed, 6 insertions(+), 82 deletions(-)

diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 0dfeb43f3d..c505353174 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1093,25 +1093,10 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
     const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f;
 
     if (leftHandEnabled) {
-        if (!_isLeftHandControlled) {
-            _leftHandControlTimeRemaining = CONTROL_DURATION;
-            _isLeftHandControlled = true;
-        }
 
         glm::vec3 handPosition = leftHandPose.trans();
         glm::quat handRotation = leftHandPose.rot();
 
-        if (_leftHandControlTimeRemaining > 0.0f) {
-            // Move hand from non-controlled position to controlled position.
-            _leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f);
-            AnimPose handPose(Vectors::ONE, handRotation, handPosition);
-            if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose,
-                                   LEFT_HAND, TO_CONTROLLED, handPose)) {
-                handPosition = handPose.trans();
-                handRotation = handPose.rot();
-            }
-        }
-
         if (!hipsEnabled) {
             // prevent the hand IK targets from intersecting the body capsule
             glm::vec3 displacement;
@@ -1124,9 +1109,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
         _animVars.set("leftHandRotation", handRotation);
         _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
 
-        _lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
-        _isLeftHandControlled = true;
-
         // compute pole vector
         int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand");
         int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm");
@@ -1154,47 +1136,17 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
         _prevLeftHandPoleVectorValid = false;
         _animVars.set("leftHandPoleVectorEnabled", false);
 
-        if (_isLeftHandControlled) {
-            _leftHandRelaxTimeRemaining = RELAX_DURATION;
-            _isLeftHandControlled = false;
-        }
+        _animVars.unset("leftHandPosition");
+        _animVars.unset("leftHandRotation");
+        _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
 
-        if (_leftHandRelaxTimeRemaining > 0.0f) {
-            // Move hand from controlled position to non-controlled position.
-            _leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f);
-            AnimPose handPose;
-            if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose,
-                                   LEFT_HAND, FROM_CONTROLLED, handPose)) {
-                _animVars.set("leftHandPosition", handPose.trans());
-                _animVars.set("leftHandRotation", handPose.rot());
-                _animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
-            }
-        } else {
-            _animVars.unset("leftHandPosition");
-            _animVars.unset("leftHandRotation");
-            _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
-        }
     }
 
     if (rightHandEnabled) {
-        if (!_isRightHandControlled) {
-            _rightHandControlTimeRemaining = CONTROL_DURATION;
-            _isRightHandControlled = true;
-        }
 
         glm::vec3 handPosition = rightHandPose.trans();
         glm::quat handRotation = rightHandPose.rot();
 
-        if (_rightHandControlTimeRemaining > 0.0f) {
-            // Move hand from non-controlled position to controlled position.
-            _rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f);
-            AnimPose handPose(Vectors::ONE, handRotation, handPosition);
-            if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED, handPose)) {
-                handPosition = handPose.trans();
-                handRotation = handPose.rot();
-            }
-        }
-
         if (!hipsEnabled) {
             // prevent the hand IK targets from intersecting the body capsule
             glm::vec3 displacement;
@@ -1207,9 +1159,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
         _animVars.set("rightHandRotation", handRotation);
         _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
 
-        _lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
-        _isRightHandControlled = true;
-
         // compute pole vector
         int handJointIndex = _animSkeleton->nameToJointIndex("RightHand");
         int armJointIndex = _animSkeleton->nameToJointIndex("RightArm");
@@ -1237,25 +1186,9 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
         _prevRightHandPoleVectorValid = false;
         _animVars.set("rightHandPoleVectorEnabled", false);
 
-        if (_isRightHandControlled) {
-            _rightHandRelaxTimeRemaining = RELAX_DURATION;
-            _isRightHandControlled = false;
-        }
-
-        if (_rightHandRelaxTimeRemaining > 0.0f) {
-            // Move hand from controlled position to non-controlled position.
-            _rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f);
-            AnimPose handPose;
-            if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND, FROM_CONTROLLED, handPose)) {
-                _animVars.set("rightHandPosition", handPose.trans());
-                _animVars.set("rightHandRotation", handPose.rot());
-                _animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
-            }
-        } else {
-            _animVars.unset("rightHandPosition");
-            _animVars.unset("rightHandRotation");
-            _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
-        }
+        _animVars.unset("rightHandPosition");
+        _animVars.unset("rightHandRotation");
+        _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
     }
 }
 
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index c17a7b9c8f..ec13d98613 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -343,15 +343,6 @@ protected:
     bool transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
                             bool isToControlled, AnimPose& returnHandPose);
 
-    bool _isLeftHandControlled { false };
-    bool _isRightHandControlled { false };
-    float _leftHandControlTimeRemaining { 0.0f };
-    float _rightHandControlTimeRemaining { 0.0f };
-    float _leftHandRelaxTimeRemaining { 0.0f };
-    float _rightHandRelaxTimeRemaining { 0.0f };
-    AnimPose _lastLeftHandControlledPose;
-    AnimPose _lastRightHandControlledPose;
-
     glm::vec3 _prevRightFootPoleVector { Vectors::UNIT_Z };
     bool _prevRightFootPoleVectorValid { false };
 

From 7ed1382ac98b4ff0dc0479713126e3832c9b554a Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Mon, 3 Jul 2017 16:32:46 -0700
Subject: [PATCH 06/12] ik level interpolation of incoming targets

---
 .../animation/src/AnimInverseKinematics.cpp   | 140 +++++++++++++-----
 .../animation/src/AnimInverseKinematics.h     |  13 +-
 2 files changed, 114 insertions(+), 39 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index 5ea628d1f4..dd13279786 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -23,6 +23,8 @@
 #include "CubicHermiteSpline.h"
 #include "AnimUtil.h"
 
+static const float JOINT_CHAIN_INTERP_TIME = 0.25f;
+
 static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo,
                                  int indexA, int indexB,
                                  const AnimInverseKinematics::JointInfo** jointInfoA,
@@ -171,6 +173,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
         IKTarget target;
         if (targetVar.jointIndex != -1) {
             target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
+            target.setIndex(targetVar.jointIndex);
             if (target.getType() != IKTarget::Type::Unknown) {
                 AnimPose absPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
                 glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, absPose.rot());
@@ -178,7 +181,6 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
                 float weight = animVars.lookup(targetVar.weightVar, targetVar.weight);
 
                 target.setPose(rotation, translation);
-                target.setIndex(targetVar.jointIndex);
                 target.setWeight(weight);
                 target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients);
 
@@ -204,7 +206,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
     }
 }
 
-void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets) {
+void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec) {
     // compute absolute poses that correspond to relative target poses
     AnimPoseVec absolutePoses;
     absolutePoses.resize(_relativePoses.size());
@@ -218,23 +220,10 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         accumulator.clearAndClean();
     }
 
-    // initialize a new jointChainInfoVec, this will holds the results for solving each ik chain.
-    JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
-    JointChainInfoVec jointChainInfoVec(targets.size());
-    for (size_t i = 0; i < targets.size(); i++) {
-        int chainDepth = _skeleton->getChainDepth(targets[i].getIndex());
-        jointChainInfoVec[i].jointInfoVec.reserve(chainDepth);
-        jointChainInfoVec[i].target = targets[i];
-        for (size_t j = 0; j < chainDepth; j++) {
-            jointChainInfoVec[i].jointInfoVec.push_back(defaultJointInfo);
-        }
-    }
-
-    float maxError = FLT_MAX;
+    float maxError = 0.0f;
     int numLoops = 0;
     const int MAX_IK_LOOPS = 16;
-    const float MAX_ERROR_TOLERANCE = 0.1f; // cm
-    while (maxError > MAX_ERROR_TOLERANCE && numLoops < MAX_IK_LOOPS) {
+    while (numLoops < MAX_IK_LOOPS) {
         ++numLoops;
 
         bool debug = context.getEnableDebugDrawIKChains() && numLoops == MAX_IK_LOOPS;
@@ -253,23 +242,45 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
             }
         }
 
-        // TODO: do smooth interpolation of joint chains here, if necessary.
+        // on last iteration, interpolate jointChains, if necessary
+        if (numLoops == MAX_IK_LOOPS) {
+            for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
+                if (_prevJointChainInfoVec[i].timer > 0.0f) {
+                    float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
+                    size_t chainSize = std::min(_prevJointChainInfoVec[i].jointInfoVec.size(), jointChainInfoVec[i].jointInfoVec.size());
+                    for (size_t j = 0; j < chainSize; j++) {
+                        jointChainInfoVec[i].jointInfoVec[j].rot = safeMix(_prevJointChainInfoVec[i].jointInfoVec[j].rot, jointChainInfoVec[i].jointInfoVec[j].rot, alpha);
+                        jointChainInfoVec[i].jointInfoVec[j].trans = lerp(_prevJointChainInfoVec[i].jointInfoVec[j].trans, jointChainInfoVec[i].jointInfoVec[j].trans, alpha);
+                    }
+                }
+            }
+        }
 
         // copy jointChainInfoVecs into accumulators
         for (size_t i = 0; i < targets.size(); i++) {
             const std::vector<JointInfo>& jointInfoVec = jointChainInfoVec[i].jointInfoVec;
-            float weight = jointChainInfoVec[i].target.getWeight();
-            for (size_t j = 0; j < jointInfoVec.size(); j++) {
-                const JointInfo& info = jointInfoVec[j];
-                if (info.jointIndex >= 0) {
-                    _rotationAccumulators[info.jointIndex].add(info.rot, weight);
-                    _translationAccumulators[info.jointIndex].add(info.trans, weight);
+
+            // don't accumulate disabled or rotation only ik targets.
+            IKTarget::Type type = jointChainInfoVec[i].target.getType();
+            if (type != IKTarget::Type::Unknown && type != IKTarget::Type::RotationOnly) {
+                float weight = jointChainInfoVec[i].target.getWeight();
+                if (weight > 0.0f) {
+                    for (size_t j = 0; j < jointInfoVec.size(); j++) {
+                        const JointInfo& info = jointInfoVec[j];
+                        if (info.jointIndex >= 0) {
+                            _rotationAccumulators[info.jointIndex].add(info.rot, weight);
+                            _translationAccumulators[info.jointIndex].add(info.trans, weight);
+                        }
+                    }
                 }
             }
         }
 
         // harvest accumulated rotations and apply the average
         for (int i = 0; i < (int)_relativePoses.size(); ++i) {
+            if (i == _hipsIndex) {
+                continue;  // don't apply accumulators to hips
+            }
             if (_rotationAccumulators[i].size() > 0) {
                 _relativePoses[i].rot() = _rotationAccumulators[i].getAverage();
                 _rotationAccumulators[i].clear();
@@ -324,6 +335,28 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
             absolutePoses[tipIndex].rot() = targetRotation;
         }
     }
+
+    for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
+        _prevJointChainInfoVec[i].timer = _prevJointChainInfoVec[i].timer - dt;
+        if (_prevJointChainInfoVec[i].timer <= 0.0f) {
+            _prevJointChainInfoVec[i] = jointChainInfoVec[i];
+            // store relative poses into unknown/rotation only joint chains.
+            // so we have something to interpolate from if this chain is activated.
+            IKTarget::Type type = _prevJointChainInfoVec[i].target.getType();
+            if (type == IKTarget::Type::Unknown || type == IKTarget::Type::RotationOnly) {
+                for (size_t j = 0; j < _prevJointChainInfoVec[i].jointInfoVec.size(); j++) {
+                    auto& info = _prevJointChainInfoVec[i].jointInfoVec[j];
+                    if (info.jointIndex >= 0) {
+                        info.rot = _relativePoses[info.jointIndex].rot();
+                        info.trans = _relativePoses[info.jointIndex].trans();
+                    } else {
+                        info.rot = Quaternions::IDENTITY;
+                        info.trans = glm::vec3(0.0f);
+                    }
+                }
+            }
+        }
+    }
 }
 
 void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
@@ -638,7 +671,7 @@ static CubicHermiteSplineFunctorWithArcLength computeSplineFromTipAndBase(const
 }
 
 // pre-compute information about each joint influeced by this spline IK target.
-void AnimInverseKinematics::computeSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) {
+void AnimInverseKinematics::computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) const {
     std::vector<SplineJointInfo> splineJointInfoVec;
 
     // build spline between the default poses.
@@ -691,13 +724,13 @@ void AnimInverseKinematics::computeSplineJointInfosForIKTarget(const AnimContext
     _splineJointInfoMap[target.getIndex()] = splineJointInfoVec;
 }
 
-const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics::findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) {
+const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics::findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) const {
     // find or create splineJointInfo for this target
     auto iter = _splineJointInfoMap.find(target.getIndex());
     if (iter != _splineJointInfoMap.end()) {
         return &(iter->second);
     } else {
-        computeSplineJointInfosForIKTarget(context, target);
+        computeAndCacheSplineJointInfosForIKTarget(context, target);
         auto iter = _splineJointInfoMap.find(target.getIndex());
         if (iter != _splineJointInfoMap.end()) {
             return &(iter->second);
@@ -707,9 +740,8 @@ const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics
     return nullptr;
 }
 
-// AJT: TODO: make this const someday
 void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                                                  bool debug, JointChainInfo& jointChainInfoOut) {
+                                                  bool debug, JointChainInfo& jointChainInfoOut) const {
 
     const int baseIndex = _hipsIndex;
 
@@ -854,18 +886,57 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
             _relativePoses = underPoses;
         } else {
 
+            JointChainInfoVec jointChainInfoVec(targets.size());
+            {
+                PROFILE_RANGE_EX(simulation_animation, "ik/jointChainInfo", 0xffff00ff, 0);
+
+                // initialize a new jointChainInfoVec, this will holds the results for solving each ik chain.
+                JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
+                for (size_t i = 0; i < targets.size(); i++) {
+                    int chainDepth = _skeleton->getChainDepth(targets[i].getIndex());
+                    jointChainInfoVec[i].jointInfoVec.reserve(chainDepth);
+                    jointChainInfoVec[i].target = targets[i];
+                    int index = targets[i].getIndex();
+                    for (size_t j = 0; j < chainDepth; j++) {
+                        jointChainInfoVec[i].jointInfoVec.push_back(defaultJointInfo);
+                        jointChainInfoVec[i].jointInfoVec[j].jointIndex = index;
+                        index = _skeleton->getParentIndex(index);
+                    }
+                }
+
+                _prevJointChainInfoVec.resize(jointChainInfoVec.size());
+                for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
+                    if (_prevJointChainInfoVec[i].timer <= 0.0f &&
+                        (jointChainInfoVec[i].target.getType() != _prevJointChainInfoVec[i].target.getType() ||
+                         jointChainInfoVec[i].target.getPoleVectorEnabled() != _prevJointChainInfoVec[i].target.getPoleVectorEnabled())) {
+                        _prevJointChainInfoVec[i].timer = JOINT_CHAIN_INTERP_TIME;
+                    }
+                }
+            }
+
             {
                 PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
 
                 if (_hipsTargetIndex >= 0 && _hipsTargetIndex < (int)targets.size()) {
                     // slam the hips to match the _hipsTarget
+
                     AnimPose absPose = targets[_hipsTargetIndex].getPose();
+
                     int parentIndex = _skeleton->getParentIndex(targets[_hipsTargetIndex].getIndex());
-                    if (parentIndex != -1) {
-                        _relativePoses[_hipsIndex] = _skeleton->getAbsolutePose(parentIndex, _relativePoses).inverse() * absPose;
-                    } else {
-                        _relativePoses[_hipsIndex] = absPose;
+                    AnimPose parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
+
+                    // do smooth interpolation of hips here, if necessary.
+                    if (_prevJointChainInfoVec[_hipsTargetIndex].timer > 0.0f) {
+                        float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[_hipsTargetIndex].timer) / JOINT_CHAIN_INTERP_TIME;
+
+                        auto& info = _prevJointChainInfoVec[_hipsTargetIndex].jointInfoVec[0];
+                        AnimPose prevHipsRelPose(info.rot, info.trans);
+                        AnimPose prevHipsAbsPose = parentAbsPose * prevHipsRelPose;
+                        ::blend(1, &prevHipsAbsPose, &absPose, alpha, &absPose);
                     }
+
+                    _relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
+
                 } else {
                     // if there is no hips target, shift hips according to the _hipsOffset from the previous frame
                     float offsetLength = glm::length(_hipsOffset);
@@ -924,8 +995,9 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
 
             {
                 PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
+
                 preconditionRelativePosesToAvoidLimbLock(context, targets);
-                solve(context, targets);
+                solve(context, targets, dt, jointChainInfoVec);
             }
 
             if (_hipsTargetIndex < 0) {
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index fb462cbf50..d5fc5a6a8c 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -36,6 +36,7 @@ public:
     struct JointChainInfo {
         std::vector<JointInfo> jointInfoVec;
         IKTarget target;
+        float timer { 0.0f };
     };
 
     using JointChainInfoVec = std::vector<JointChainInfo>;
@@ -78,11 +79,11 @@ public:
 
 protected:
     void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
-    void solve(const AnimContext& context, const std::vector<IKTarget>& targets);
+    void solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec);
     void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
                             bool debug, JointChainInfo& jointChainInfoOut) const;
     void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
-                               bool debug, JointChainInfo& jointChainInfoOut);
+                               bool debug, JointChainInfo& jointChainInfoOut) const;
     virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
     void debugDrawIKChain(const JointChainInfo& jointChainInfo, const AnimContext& context) const;
     void debugDrawRelativePoses(const AnimContext& context) const;
@@ -99,8 +100,8 @@ protected:
         AnimPose offsetPose;  // local offset from the spline to the joint.
     };
 
-    void computeSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target);
-    const std::vector<SplineJointInfo>* findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target);
+    void computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) const;
+    const std::vector<SplineJointInfo>* findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) const;
 
     // for AnimDebugDraw rendering
     virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }
@@ -144,7 +145,7 @@ protected:
     AnimPoseVec _relativePoses; // current relative poses
     AnimPoseVec _limitCenterPoses;  // relative
 
-    std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
+    mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
 
     // experimental data for moving hips during IK
     glm::vec3 _hipsOffset { Vectors::ZERO };
@@ -164,6 +165,8 @@ protected:
     AnimPose _uncontrolledLeftHandPose { AnimPose() };
     AnimPose _uncontrolledRightHandPose { AnimPose() };
     AnimPose _uncontrolledHipsPose { AnimPose() };
+
+    JointChainInfoVec _prevJointChainInfoVec;
 };
 
 #endif // hifi_AnimInverseKinematics_h

From 1a24d4d8ec060f87ac29e8a3bf6d119bdb513ccd Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Wed, 5 Jul 2017 09:31:02 -0700
Subject: [PATCH 07/12] added safeLerp, shortest angle quat lerp with post
 normalize

---
 .../animation/src/AnimInverseKinematics.cpp     | 17 +++++++----------
 libraries/animation/src/AnimUtil.cpp            |  2 +-
 libraries/animation/src/AnimUtil.h              | 10 ++++++++++
 3 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index dd13279786..f0cd0dea98 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -491,9 +491,8 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
                             glm::quat twistPart;
                             glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
                             swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
-                            float dotSign = copysignf(1.0f, twistPart.w);
                             const float LIMIT_LEAK_FRACTION = 0.1f;
-                            deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, LIMIT_LEAK_FRACTION)) * deltaRotation;
+                            deltaRotation = safeLerp(glm::quat(), twistPart, LIMIT_LEAK_FRACTION);
                         }
                     }
                 }
@@ -502,9 +501,8 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
             // An HmdHead target slaves the orientation of the end-effector by distributing rotation
             // deltas up the hierarchy.  Its target position is enforced later (by shifting the hips).
             deltaRotation = target.getRotation() * glm::inverse(tipOrientation);
-            float dotSign = copysignf(1.0f, deltaRotation.w);
             const float ANGLE_DISTRIBUTION_FACTOR = 0.45f;
-            deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * deltaRotation, ANGLE_DISTRIBUTION_FACTOR));
+            deltaRotation = safeLerp(glm::quat(), deltaRotation, ANGLE_DISTRIBUTION_FACTOR);
         }
 
         // compute joint's new parent-relative rotation after swing
@@ -761,7 +759,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
 
     // This prevents the rotation interpolation from rotating the wrong physical way (but correct mathematical way)
     // when the head is arched backwards very far.
-    glm::quat halfRot = glm::normalize(glm::lerp(basePose.rot(), tipPose.rot(), 0.5f));
+    glm::quat halfRot = safeLerp(basePose.rot(), tipPose.rot(), 0.5f);
     if (glm::dot(halfRot * Vectors::UNIT_Z, basePose.rot() * Vectors::UNIT_Z) < 0.0f) {
         tipPose.rot() = -tipPose.rot();
     }
@@ -784,7 +782,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
             if (target.getIndex() == _headIndex) {
                 rotT = t * t;
             }
-            glm::quat twistRot = glm::normalize(glm::lerp(basePose.rot(), tipPose.rot(), rotT));
+            glm::quat twistRot = safeLerp(basePose.rot(), tipPose.rot(), rotT);
 
             // compute the rotation by using the derivative of the spline as the y-axis, and the twistRot x-axis
             glm::vec3 y = glm::normalize(spline.d(t));
@@ -1682,7 +1680,7 @@ void AnimInverseKinematics::debugDrawConstraints(const AnimContext& context) con
 
                     const int NUM_SWING_STEPS = 10;
                     for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
-                        glm::quat rot = glm::normalize(glm::lerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS)));
+                        glm::quat rot = safeLerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS));
                         glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_Y);
                         DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
                     }
@@ -1700,7 +1698,7 @@ void AnimInverseKinematics::debugDrawConstraints(const AnimContext& context) con
 
                         const int NUM_SWING_STEPS = 10;
                         for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
-                            glm::quat rot = glm::normalize(glm::lerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS)));
+                            glm::quat rot = safeLerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS));
                             glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_X);
                             DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
                         }
@@ -1740,10 +1738,9 @@ void AnimInverseKinematics::blendToPoses(const AnimPoseVec& targetPoses, const A
     // relax toward poses
     int numJoints = (int)_relativePoses.size();
     for (int i = 0; i < numJoints; ++i) {
-        float dotSign = copysignf(1.0f, glm::dot(_relativePoses[i].rot(), targetPoses[i].rot()));
         if (_rotationAccumulators[i].isDirty()) {
             // this joint is affected by IK --> blend toward the targetPoses rotation
-            _relativePoses[i].rot() = glm::normalize(glm::lerp(_relativePoses[i].rot(), dotSign * targetPoses[i].rot(), blendFactor));
+            _relativePoses[i].rot() = safeLerp(_relativePoses[i].rot(), targetPoses[i].rot(), blendFactor);
         } else {
             // this joint is NOT affected by IK --> slam to underPoses rotation
             _relativePoses[i].rot() = underPoses[i].rot();
diff --git a/libraries/animation/src/AnimUtil.cpp b/libraries/animation/src/AnimUtil.cpp
index a4659f1e76..bcf30642e8 100644
--- a/libraries/animation/src/AnimUtil.cpp
+++ b/libraries/animation/src/AnimUtil.cpp
@@ -28,7 +28,7 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A
         }
 
         result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha);
-        result[i].rot() = glm::normalize(glm::lerp(aPose.rot(), q2, alpha));
+        result[i].rot() = safeLerp(aPose.rot(), bPose.rot(), alpha);
         result[i].trans() = lerp(aPose.trans(), bPose.trans(), alpha);
     }
 }
diff --git a/libraries/animation/src/AnimUtil.h b/libraries/animation/src/AnimUtil.h
index 055fd630eb..d215fdc654 100644
--- a/libraries/animation/src/AnimUtil.h
+++ b/libraries/animation/src/AnimUtil.h
@@ -21,4 +21,14 @@ glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
 float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
                      const QString& id, AnimNode::Triggers& triggersOut);
 
+inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
+    // adjust signs if necessary
+    glm::quat bTemp = b;
+    float dot = glm::dot(a, bTemp);
+    if (dot < 0.0f) {
+        bTemp = -bTemp;
+    }
+    return glm::normalize(glm::lerp(a, bTemp, alpha));
+}
+
 #endif

From 06d512dab90f2444bc5d968ea5f6b21d4a665b53 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Wed, 5 Jul 2017 10:43:24 -0700
Subject: [PATCH 08/12] Warning fixes

---
 libraries/animation/src/AnimInverseKinematics.cpp | 2 +-
 libraries/animation/src/Rig.cpp                   | 8 --------
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index f0cd0dea98..7e13c13650 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -891,7 +891,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                 // initialize a new jointChainInfoVec, this will holds the results for solving each ik chain.
                 JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
                 for (size_t i = 0; i < targets.size(); i++) {
-                    int chainDepth = _skeleton->getChainDepth(targets[i].getIndex());
+                    size_t chainDepth = (size_t)_skeleton->getChainDepth(targets[i].getIndex());
                     jointChainInfoVec[i].jointInfoVec.reserve(chainDepth);
                     jointChainInfoVec[i].target = targets[i];
                     int index = targets[i].getIndex();
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index c505353174..9cc09addb3 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1082,14 +1082,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
     const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, bodyCapsuleHalfHeight, 0);
 
     const float HAND_RADIUS = 0.05f;
-
-    const float RELAX_DURATION = 0.6f;
-    const float CONTROL_DURATION = 0.4f;
-    const bool TO_CONTROLLED = true;
-    const bool FROM_CONTROLLED = false;
-    const bool LEFT_HAND = true;
-    const bool RIGHT_HAND = false;
-
     const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f;
 
     if (leftHandEnabled) {

From bd8d6280a8a4636648b840c2fcfb8d80abe756b8 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 7 Jul 2017 09:29:57 -0700
Subject: [PATCH 09/12] Interpolate out of ik chains when they are disabled

---
 libraries/animation/src/AnimInverseKinematics.cpp | 14 ++++++++++++--
 libraries/animation/src/IKTarget.h                |  2 +-
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index 7e13c13650..a0cb8432d9 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -252,6 +252,14 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
                         jointChainInfoVec[i].jointInfoVec[j].rot = safeMix(_prevJointChainInfoVec[i].jointInfoVec[j].rot, jointChainInfoVec[i].jointInfoVec[j].rot, alpha);
                         jointChainInfoVec[i].jointInfoVec[j].trans = lerp(_prevJointChainInfoVec[i].jointInfoVec[j].trans, jointChainInfoVec[i].jointInfoVec[j].trans, alpha);
                     }
+
+                    // if joint chain was just disabled, ramp the weight toward zero.
+                    if (_prevJointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown &&
+                        jointChainInfoVec[i].target.getType() == IKTarget::Type::Unknown) {
+                        IKTarget newTarget = _prevJointChainInfoVec[i].target;
+                        newTarget.setWeight(alpha);
+                        jointChainInfoVec[i].target = newTarget;
+                    }
                 }
             }
         }
@@ -336,6 +344,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         }
     }
 
+    // copy jointChainInfoVec into _prevJointChainInfoVec, and update timers
     for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
         _prevJointChainInfoVec[i].timer = _prevJointChainInfoVec[i].timer - dt;
         if (_prevJointChainInfoVec[i].timer <= 0.0f) {
@@ -888,7 +897,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
             {
                 PROFILE_RANGE_EX(simulation_animation, "ik/jointChainInfo", 0xffff00ff, 0);
 
-                // initialize a new jointChainInfoVec, this will holds the results for solving each ik chain.
+                // initialize a new jointChainInfoVec, this will hold the results for solving each ik chain.
                 JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
                 for (size_t i = 0; i < targets.size(); i++) {
                     size_t chainDepth = (size_t)_skeleton->getChainDepth(targets[i].getIndex());
@@ -902,6 +911,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                     }
                 }
 
+                // identity joint chains that have changed types this frame.
                 _prevJointChainInfoVec.resize(jointChainInfoVec.size());
                 for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
                     if (_prevJointChainInfoVec[i].timer <= 0.0f &&
@@ -923,7 +933,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                     int parentIndex = _skeleton->getParentIndex(targets[_hipsTargetIndex].getIndex());
                     AnimPose parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
 
-                    // do smooth interpolation of hips here, if necessary.
+                    // do smooth interpolation of hips, if necessary.
                     if (_prevJointChainInfoVec[_hipsTargetIndex].timer > 0.0f) {
                         float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[_hipsTargetIndex].timer) / JOINT_CHAIN_INTERP_TIME;
 
diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h
index a86ae0ca8b..325a1b40b6 100644
--- a/libraries/animation/src/IKTarget.h
+++ b/libraries/animation/src/IKTarget.h
@@ -56,7 +56,7 @@ private:
     glm::vec3 _poleReferenceVector;
     bool _poleVectorEnabled { false };
     int _index { -1 };
-    Type _type { Type::RotationAndPosition };
+    Type _type { Type::Unknown };
     float _weight { 0.0f };
     float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
     size_t _numFlexCoefficients;

From 1cdc0071f3cfb489831f90d04171c6418d9d4906 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Mon, 10 Jul 2017 16:17:25 -0700
Subject: [PATCH 10/12] Fixed issue with hips and chest not ramping off
 properly.

---
 .../animation/src/AnimInverseKinematics.cpp   | 99 +++++++++++--------
 .../animation/src/AnimInverseKinematics.h     | 11 +--
 libraries/animation/src/Rig.cpp               | 22 -----
 libraries/animation/src/Rig.h                 |  3 -
 4 files changed, 62 insertions(+), 73 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index a0cb8432d9..8c86ada43c 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -257,7 +257,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
                     if (_prevJointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown &&
                         jointChainInfoVec[i].target.getType() == IKTarget::Type::Unknown) {
                         IKTarget newTarget = _prevJointChainInfoVec[i].target;
-                        newTarget.setWeight(alpha);
+                        newTarget.setWeight((1.0f - alpha) * _prevJointChainInfoVec[i].target.getWeight());
                         jointChainInfoVec[i].target = newTarget;
                     }
                 }
@@ -349,6 +349,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
         _prevJointChainInfoVec[i].timer = _prevJointChainInfoVec[i].timer - dt;
         if (_prevJointChainInfoVec[i].timer <= 0.0f) {
             _prevJointChainInfoVec[i] = jointChainInfoVec[i];
+            _prevJointChainInfoVec[i].target = targets[i];
             // store relative poses into unknown/rotation only joint chains.
             // so we have something to interpolate from if this chain is activated.
             IKTarget::Type type = _prevJointChainInfoVec[i].target.getType();
@@ -849,6 +850,24 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
     return _relativePoses;
 }
 
+AnimPose AnimInverseKinematics::applyHipsOffset() const {
+    glm::vec3 hipsOffset = _hipsOffset;
+    AnimPose relHipsPose = _relativePoses[_hipsIndex];
+    float offsetLength = glm::length(hipsOffset);
+    const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
+    if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
+        float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
+        glm::vec3 scaledHipsOffset = scaleFactor * hipsOffset;
+        if (_hipsParentIndex == -1) {
+            relHipsPose.trans() = _relativePoses[_hipsIndex].trans() + scaledHipsOffset;
+        } else {
+            AnimPose absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
+            absHipsPose.trans() += scaledHipsOffset;
+            relHipsPose = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
+        }
+    }
+    return relHipsPose;
+}
 
 //virtual
 const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
@@ -925,7 +944,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
             {
                 PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
 
-                if (_hipsTargetIndex >= 0 && _hipsTargetIndex < (int)targets.size()) {
+                if (_hipsTargetIndex >= 0 && _hipsTargetIndex >= 0 && _hipsTargetIndex < (int)targets.size()) {
                     // slam the hips to match the _hipsTarget
 
                     AnimPose absPose = targets[_hipsTargetIndex].getPose();
@@ -934,7 +953,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                     AnimPose parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
 
                     // do smooth interpolation of hips, if necessary.
-                    if (_prevJointChainInfoVec[_hipsTargetIndex].timer > 0.0f) {
+                    if (_prevJointChainInfoVec[_hipsTargetIndex].timer > 0.0f && _prevJointChainInfoVec[_hipsTargetIndex].jointInfoVec.size() > 0) {
                         float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[_hipsTargetIndex].timer) / JOINT_CHAIN_INTERP_TIME;
 
                         auto& info = _prevJointChainInfoVec[_hipsTargetIndex].jointInfoVec[0];
@@ -944,22 +963,36 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                     }
 
                     _relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
+                    _relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
+                    _hipsOffset = Vectors::ZERO;
+
+                } else if (_hipsIndex >= 0) {
 
-                } else {
                     // if there is no hips target, shift hips according to the _hipsOffset from the previous frame
-                    float offsetLength = glm::length(_hipsOffset);
-                    const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
-                    if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) {
-                        float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
-                        glm::vec3 hipsOffset = scaleFactor * _hipsOffset;
-                        if (_hipsParentIndex == -1) {
-                            _relativePoses[_hipsIndex].trans() = _relativePoses[_hipsIndex].trans() + hipsOffset;
-                        } else {
-                            auto absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
-                            absHipsPose.trans() += hipsOffset;
-                            _relativePoses[_hipsIndex] = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
+                    AnimPose relHipsPose = applyHipsOffset();
+
+                    // determine if we should begin interpolating the hips.
+                    for (size_t i = 0; i < targets.size(); i++) {
+                        if (_prevJointChainInfoVec[i].target.getIndex() == _hipsIndex) {
+                            if (_prevJointChainInfoVec[i].timer > 0.0f) {
+                                // smoothly lerp in hipsOffset
+                                float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
+                                AnimPose prevRelHipsPose(_prevJointChainInfoVec[i].jointInfoVec[0].rot, _prevJointChainInfoVec[i].jointInfoVec[0].trans);
+                                ::blend(1, &prevRelHipsPose, &relHipsPose, alpha, &relHipsPose);
+                            }
+                            break;
                         }
                     }
+
+                    _relativePoses[_hipsIndex] = relHipsPose;
+                }
+
+                // if there is an active jointChainInfo for the hips store the post shifted hips into it.
+                // This is so we have a valid pose to interplate from when the hips target is disabled.
+                if (_hipsTargetIndex >= 0) {
+                    // AJT: TODO: WILL THIS WORK if hips aren't the root of skeleton?
+                    jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].rot = _relativePoses[_hipsIndex].rot();
+                    jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].trans = _relativePoses[_hipsIndex].trans();
                 }
 
                 // update all HipsRelative targets to account for the hips shift/ik target.
@@ -1010,9 +1043,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
 
             if (_hipsTargetIndex < 0) {
                 PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
-                computeHipsOffset(targets, underPoses, dt);
-            } else {
-                _hipsOffset = Vectors::ZERO;
+                _hipsOffset = computeHipsOffset(targets, underPoses, dt, _hipsOffset);
             }
         }
 
@@ -1021,23 +1052,15 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
         }
     }
 
-    if (_leftHandIndex > -1) {
-        _uncontrolledLeftHandPose = _skeleton->getAbsolutePose(_leftHandIndex, underPoses);
-    }
-    if (_rightHandIndex > -1) {
-        _uncontrolledRightHandPose = _skeleton->getAbsolutePose(_rightHandIndex, underPoses);
-    }
-    if (_hipsIndex > -1) {
-        _uncontrolledHipsPose = _skeleton->getAbsolutePose(_hipsIndex, underPoses);
-    }
-
     return _relativePoses;
 }
 
-void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt) {
+glm::vec3 AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const {
+
     // measure new _hipsOffset for next frame
     // by looking for discrepancies between where a targeted endEffector is
     // and where it wants to be (after IK solutions are done)
+    glm::vec3 hipsOffset = prevHipsOffset;
     glm::vec3 newHipsOffset = Vectors::ZERO;
     for (auto& target: targets) {
         int targetIndex = target.getIndex();
@@ -1053,9 +1076,9 @@ void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targe
             } else if (target.getType() == IKTarget::Type::HmdHead) {
                 // we want to shift the hips to bring the head to its designated position
                 glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
-                _hipsOffset += target.getTranslation() - actual;
+                hipsOffset += target.getTranslation() - actual;
                 // and ignore all other targets
-                newHipsOffset = _hipsOffset;
+                newHipsOffset = hipsOffset;
                 break;
             } else if (target.getType() == IKTarget::Type::RotationAndPosition) {
                 glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
@@ -1075,16 +1098,18 @@ void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targe
         }
     }
 
-    // smooth transitions by relaxing _hipsOffset toward the new value
+    // smooth transitions by relaxing hipsOffset toward the new value
     const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
     float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ?  dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
-    _hipsOffset += (newHipsOffset - _hipsOffset) * tau;
+    hipsOffset += (newHipsOffset - hipsOffset) * tau;
 
     // clamp the hips offset
-    float hipsOffsetLength = glm::length(_hipsOffset);
+    float hipsOffsetLength = glm::length(hipsOffset);
     if (hipsOffsetLength > _maxHipsOffsetLength) {
-        _hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
+        hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
     }
+
+    return hipsOffset;
 }
 
 void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
@@ -1528,10 +1553,6 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
         _leftHandIndex = -1;
         _rightHandIndex = -1;
     }
-
-    _uncontrolledLeftHandPose = AnimPose();
-    _uncontrolledRightHandPose = AnimPose();
-    _uncontrolledHipsPose = AnimPose();
 }
 
 static glm::vec3 sphericalToCartesian(float phi, float theta) {
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index d5fc5a6a8c..7f7640aa24 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -73,10 +73,6 @@ public:
     void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
     void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
 
-    const AnimPose& getUncontrolledLeftHandPose() { return _uncontrolledLeftHandPose; }
-    const AnimPose& getUncontrolledRightHandPose() { return _uncontrolledRightHandPose; }
-    const AnimPose& getUncontrolledHipPose() { return _uncontrolledHipsPose; }
-
 protected:
     void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
     void solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec);
@@ -92,6 +88,7 @@ protected:
     void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
     void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
     void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
+    AnimPose applyHipsOffset() const;
 
     // used to pre-compute information about each joint influeced by a spline IK target.
     struct SplineJointInfo {
@@ -110,7 +107,7 @@ protected:
     void clearConstraints();
     void initConstraints();
     void initLimitCenterPoses();
-    void computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt);
+    glm::vec3 computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const;
 
     // no copies
     AnimInverseKinematics(const AnimInverseKinematics&) = delete;
@@ -162,10 +159,6 @@ protected:
     SolutionSource _solutionSource { SolutionSource::RelaxToUnderPoses };
     QString _solutionSourceVar;
 
-    AnimPose _uncontrolledLeftHandPose { AnimPose() };
-    AnimPose _uncontrolledRightHandPose { AnimPose() };
-    AnimPose _uncontrolledHipsPose { AnimPose() };
-
     JointChainInfoVec _prevJointChainInfoVec;
 };
 
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 9cc09addb3..aa080dfa86 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1703,25 +1703,3 @@ void Rig::computeAvatarBoundingCapsule(
     glm::vec3 rigCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum)));
     localOffsetOut = rigCenter - transformPoint(_geometryToRigTransform, rootPosition);
 }
-
-bool Rig::transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
-                             bool isToControlled, AnimPose& returnHandPose) {
-    auto ikNode = getAnimInverseKinematicsNode();
-    if (ikNode) {
-        float alpha = 1.0f - deltaTime / totalDuration;
-        const AnimPose geometryToRigTransform(_geometryToRigTransform);
-        AnimPose uncontrolledHandPose;
-        if (isLeftHand) {
-            uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose();
-        } else {
-            uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose();
-        }
-        if (isToControlled) {
-            ::blend(1, &uncontrolledHandPose, &controlledHandPose, alpha, &returnHandPose);
-        } else {
-            ::blend(1, &controlledHandPose, &uncontrolledHandPose, alpha, &returnHandPose);
-        }
-        return true;
-    }
-    return false;
-}
diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h
index ec13d98613..5293fa1fe7 100644
--- a/libraries/animation/src/Rig.h
+++ b/libraries/animation/src/Rig.h
@@ -340,9 +340,6 @@ protected:
     int _nextStateHandlerId { 0 };
     QMutex _stateMutex;
 
-    bool transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
-                            bool isToControlled, AnimPose& returnHandPose);
-
     glm::vec3 _prevRightFootPoleVector { Vectors::UNIT_Z };
     bool _prevRightFootPoleVectorValid { false };
 

From b0177c25221d59c065a385b6287ca6a48b94e965 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Mon, 10 Jul 2017 16:25:37 -0700
Subject: [PATCH 11/12] remove comment, it does indeed work

---
 libraries/animation/src/AnimInverseKinematics.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index 8c86ada43c..20b62c2724 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -990,7 +990,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                 // if there is an active jointChainInfo for the hips store the post shifted hips into it.
                 // This is so we have a valid pose to interplate from when the hips target is disabled.
                 if (_hipsTargetIndex >= 0) {
-                    // AJT: TODO: WILL THIS WORK if hips aren't the root of skeleton?
                     jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].rot = _relativePoses[_hipsIndex].rot();
                     jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].trans = _relativePoses[_hipsIndex].trans();
                 }

From de199bff9df9f42c164bf77ef501811eb2b0bbf4 Mon Sep 17 00:00:00 2001
From: "Anthony J. Thibault" <tony@highfidelity.io>
Date: Fri, 14 Jul 2017 09:47:37 -0700
Subject: [PATCH 12/12] code review feedback

---
 libraries/animation/src/AnimInverseKinematics.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp
index 20b62c2724..57c00e7183 100644
--- a/libraries/animation/src/AnimInverseKinematics.cpp
+++ b/libraries/animation/src/AnimInverseKinematics.cpp
@@ -930,7 +930,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
                     }
                 }
 
-                // identity joint chains that have changed types this frame.
+                // identify joint chains that have changed types this frame.
                 _prevJointChainInfoVec.resize(jointChainInfoVec.size());
                 for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
                     if (_prevJointChainInfoVec[i].timer <= 0.0f &&
@@ -944,7 +944,9 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
             {
                 PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
 
-                if (_hipsTargetIndex >= 0 && _hipsTargetIndex >= 0 && _hipsTargetIndex < (int)targets.size()) {
+                if (_hipsTargetIndex >= 0) {
+                    assert(_hipsTargetIndex < (int)targets.size());
+
                     // slam the hips to match the _hipsTarget
 
                     AnimPose absPose = targets[_hipsTargetIndex].getPose();