mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
initial hip translation from IK
works for 2D 3rd person but probably not well for HMD
This commit is contained in:
parent
f8956a853b
commit
03eaa95258
3 changed files with 77 additions and 8 deletions
|
@ -23,6 +23,18 @@
|
||||||
"positionVar": "leftHandPosition",
|
"positionVar": "leftHandPosition",
|
||||||
"rotationVar": "leftHandRotation"
|
"rotationVar": "leftHandRotation"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"jointName": "RightFoot",
|
||||||
|
"positionVar": "rightToePosition",
|
||||||
|
"rotationVar": "rightToeRotation",
|
||||||
|
"typeVar": "rightToeType"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"jointName": "LeftFoot",
|
||||||
|
"positionVar": "leftToePosition",
|
||||||
|
"rotationVar": "leftToeRotation",
|
||||||
|
"typeVar": "leftToeType"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"jointName": "Neck",
|
"jointName": "Neck",
|
||||||
"positionVar": "neckPosition",
|
"positionVar": "neckPosition",
|
||||||
|
|
|
@ -343,7 +343,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
// build a list of targets from _targetVarVec
|
// build a list of targets from _targetVarVec
|
||||||
std::vector<IKTarget> targets;
|
std::vector<IKTarget> targets;
|
||||||
computeTargets(animVars, targets, underPoses);
|
computeTargets(animVars, targets, underPoses);
|
||||||
|
|
||||||
if (targets.empty()) {
|
if (targets.empty()) {
|
||||||
// no IK targets but still need to enforce constraints
|
// no IK targets but still need to enforce constraints
|
||||||
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
|
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
|
||||||
|
@ -355,7 +355,45 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
++constraintItr;
|
++constraintItr;
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
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;
|
return _relativePoses;
|
||||||
|
@ -477,7 +515,7 @@ void AnimInverseKinematics::initConstraints() {
|
||||||
stConstraint->setSwingLimits(minDots);
|
stConstraint->setSwingLimits(minDots);
|
||||||
|
|
||||||
constraint = static_cast<RotationConstraint*>(stConstraint);
|
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();
|
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||||
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
||||||
|
@ -581,7 +619,7 @@ void AnimInverseKinematics::initConstraints() {
|
||||||
} else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) {
|
} else if (0 == baseName.compare("Neck", Qt::CaseInsensitive)) {
|
||||||
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
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);
|
stConstraint->setTwistLimits(-MAX_NECK_TWIST, MAX_NECK_TWIST);
|
||||||
|
|
||||||
std::vector<float> minDots;
|
std::vector<float> minDots;
|
||||||
|
@ -589,6 +627,18 @@ void AnimInverseKinematics::initConstraints() {
|
||||||
minDots.push_back(cosf(MAX_NECK_SWING));
|
minDots.push_back(cosf(MAX_NECK_SWING));
|
||||||
stConstraint->setSwingLimits(minDots);
|
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);
|
constraint = static_cast<RotationConstraint*>(stConstraint);
|
||||||
} else if (0 == baseName.compare("ForeArm", Qt::CaseInsensitive)) {
|
} else if (0 == baseName.compare("ForeArm", Qt::CaseInsensitive)) {
|
||||||
// The elbow joint rotates about the parent-frame's zAxis (-zAxis) for the Right (Left) arm.
|
// 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);
|
eConstraint->setAngleLimits(minAngle, maxAngle);
|
||||||
|
|
||||||
constraint = static_cast<RotationConstraint*>(eConstraint);
|
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.
|
// The knee joint rotates about the parent-frame's -xAxis.
|
||||||
ElbowConstraint* eConstraint = new ElbowConstraint();
|
ElbowConstraint* eConstraint = new ElbowConstraint();
|
||||||
glm::quat referenceRotation = _defaultRelativePoses[i].rot;
|
glm::quat referenceRotation = _defaultRelativePoses[i].rot;
|
||||||
|
@ -652,7 +702,7 @@ void AnimInverseKinematics::initConstraints() {
|
||||||
eConstraint->setAngleLimits(minAngle, maxAngle);
|
eConstraint->setAngleLimits(minAngle, maxAngle);
|
||||||
|
|
||||||
constraint = static_cast<RotationConstraint*>(eConstraint);
|
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();
|
SwingTwistConstraint* stConstraint = new SwingTwistConstraint();
|
||||||
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot);
|
||||||
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
stConstraint->setTwistLimits(-PI / 4.0f, PI / 4.0f);
|
||||||
|
@ -697,7 +747,9 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
|
||||||
|
|
||||||
if (skeleton) {
|
if (skeleton) {
|
||||||
initConstraints();
|
initConstraints();
|
||||||
|
_headIndex = _skeleton->nameToJointIndex("Head");
|
||||||
} else {
|
} else {
|
||||||
clearConstraints();
|
clearConstraints();
|
||||||
|
_headIndex = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,10 @@ protected:
|
||||||
void clearConstraints();
|
void clearConstraints();
|
||||||
void initConstraints();
|
void initConstraints();
|
||||||
|
|
||||||
|
// no copies
|
||||||
|
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||||
|
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
||||||
|
|
||||||
struct IKTargetVar {
|
struct IKTargetVar {
|
||||||
IKTargetVar(const QString& jointNameIn,
|
IKTargetVar(const QString& jointNameIn,
|
||||||
const QString& positionVarIn,
|
const QString& positionVarIn,
|
||||||
|
@ -85,9 +89,10 @@ protected:
|
||||||
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
|
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
|
||||||
AnimPoseVec _relativePoses; // current relative poses
|
AnimPoseVec _relativePoses; // current relative poses
|
||||||
|
|
||||||
// no copies
|
// experimental data for moving hips during IK
|
||||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
int _headIndex = -1;
|
||||||
AnimInverseKinematics& operator=(const AnimInverseKinematics&) = delete;
|
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
|
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
|
||||||
// during the the cyclic coordinate descent algorithm
|
// during the the cyclic coordinate descent algorithm
|
||||||
|
|
Loading…
Reference in a new issue