initial hip translation from IK

works for 2D 3rd person but probably not well for HMD
This commit is contained in:
Andrew Meadows 2015-10-08 16:39:25 -07:00
parent f8956a853b
commit 03eaa95258
3 changed files with 77 additions and 8 deletions

View file

@ -23,6 +23,18 @@
"positionVar": "leftHandPosition",
"rotationVar": "leftHandRotation"
},
{
"jointName": "RightFoot",
"positionVar": "rightToePosition",
"rotationVar": "rightToeRotation",
"typeVar": "rightToeType"
},
{
"jointName": "LeftFoot",
"positionVar": "leftToePosition",
"rotationVar": "leftToeRotation",
"typeVar": "leftToeType"
},
{
"jointName": "Neck",
"positionVar": "neckPosition",

View file

@ -343,7 +343,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
// build a list of targets from _targetVarVec
std::vector<IKTarget> targets;
computeTargets(animVars, targets, underPoses);
if (targets.empty()) {
// no IK targets but still need to enforce constraints
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
@ -355,7 +355,45 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
++constraintItr;
}
} else {
// shift the hips according to the offset from the previous frame
float offsetLength = glm::length(_actualHipsOffset);
const float MIN_OFFSET_LENGTH = 0.03f;
if (offsetLength > MIN_OFFSET_LENGTH) {
// but only if actual offset is long enough
float scaleFactor = ((offsetLength - MIN_OFFSET_LENGTH) / offsetLength);
_relativePoses[0].trans = underPoses[0].trans + scaleFactor * _actualHipsOffset;
}
solveWithCyclicCoordinateDescent(targets);
// compute the new target hips offset (for next frame)
// by looking for discrepancies between where a targeted endEffector is
// and where it wants to be (after IK solutions are done)
_targetHipsOffset = Vectors::ZERO;
for (auto& target: targets) {
if (target.index == _headIndex && _headIndex != -1) {
// special handling for headTarget
AnimPose headUnderPose = _skeleton->getAbsolutePose(_headIndex, underPoses);
AnimPose headOverPose = headUnderPose;
if (target.type == IKTarget::Type::RotationOnly) {
headOverPose = _skeleton->getAbsolutePose(_headIndex, _relativePoses);
} else if (target.type == IKTarget::Type::RotationAndPosition) {
headOverPose = target.pose;
}
glm::vec3 headOffset = headOverPose.trans - headUnderPose.trans;
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
_targetHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * headOffset;
} else if (target.type == IKTarget::Type::RotationAndPosition) {
glm::vec3 actualPosition = _skeleton->getAbsolutePose(target.index, _relativePoses).trans;
glm::vec3 targetPosition = target.pose.trans;
_targetHipsOffset += targetPosition - actualPosition;
}
}
// smooth transitions by relaxing targetHipsOffset onto actualHipsOffset over some timescale
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
glm::vec3 deltaOffset = (_targetHipsOffset - _actualHipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
_actualHipsOffset += deltaOffset;
}
}
return _relativePoses;
@ -477,7 +515,7 @@ void AnimInverseKinematics::initConstraints() {
stConstraint->setSwingLimits(minDots);
constraint = static_cast<RotationConstraint*>(stConstraint);
} else if (0 == baseName.compare("UpLegXXX", Qt::CaseInsensitive)) {
} else if (0 == baseName.compare("UpLeg", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
@ -581,7 +619,7 @@ void AnimInverseKinematics::initConstraints() {
} else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
const float MAX_NECK_TWIST = PI / 2.0f;
const float MAX_NECK_TWIST = PI / 4.0f;
stConstraint->setTwistLimits(-MAX_NECK_TWIST, MAX_NECK_TWIST);
std::vector<float> minDots;
@ -589,6 +627,18 @@ void AnimInverseKinematics::initConstraints() {
minDots.push_back(cosf(MAX_NECK_SWING));
stConstraint->setSwingLimits(minDots);
constraint = static_cast<RotationConstraint*>(stConstraint);
} else if (0 == baseName.compare("Head", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
const float MAX_HEAD_TWIST = PI / 4.0f;
stConstraint->setTwistLimits(-MAX_HEAD_TWIST, MAX_HEAD_TWIST);
std::vector<float> minDots;
const float MAX_HEAD_SWING = PI / 4.0f;
minDots.push_back(cosf(MAX_HEAD_SWING));
stConstraint->setSwingLimits(minDots);
constraint = static_cast<RotationConstraint*>(stConstraint);
} else if (0 == baseName.compare("ForeArm", Qt::CaseInsensitive)) {
// The elbow joint rotates about the parent-frame's zAxis (-zAxis) for the Right (Left) arm.
@ -621,7 +671,7 @@ void AnimInverseKinematics::initConstraints() {
eConstraint->setAngleLimits(minAngle, maxAngle);
constraint = static_cast<RotationConstraint*>(eConstraint);
} else if (0 == baseName.compare("LegXXX", Qt::CaseInsensitive)) {
} else if (0 == baseName.compare("Leg", Qt::CaseInsensitive)) {
// The knee joint rotates about the parent-frame's -xAxis.
ElbowConstraint* eConstraint = new ElbowConstraint();
glm::quat referenceRotation = _defaultRelativePoses[i].rot;
@ -652,7 +702,7 @@ void AnimInverseKinematics::initConstraints() {
eConstraint->setAngleLimits(minAngle, maxAngle);
constraint = static_cast<RotationConstraint*>(eConstraint);
} else if (0 == baseName.compare("FootXXX", Qt::CaseInsensitive)) {
} else if (0 == baseName.compare("Foot", Qt::CaseInsensitive)) {
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
@ -697,7 +747,9 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
if (skeleton) {
initConstraints();
_headIndex = _skeleton->nameToJointIndex("Head");
} else {
clearConstraints();
_headIndex = -1;
}
}

View file

@ -60,6 +60,10 @@ protected:
void clearConstraints();
void initConstraints();
// no copies
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
struct IKTargetVar {
IKTargetVar(const QString& jointNameIn,
const QString& positionVarIn,
@ -85,9 +89,10 @@ protected:
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
AnimPoseVec _relativePoses; // current relative poses
// no copies
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
// experimental data for moving hips during IK
int _headIndex = -1;
glm::vec3 _targetHipsOffset = Vectors::ZERO; // offset we want
glm::vec3 _actualHipsOffset = Vectors::ZERO; // offset we have
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
// during the the cyclic coordinate descent algorithm