experimental HMD hips tracking

This commit is contained in:
U-GAPOS\andrew 2015-10-10 19:23:21 -07:00 committed by Andrew Meadows
parent 35d2a5b5ea
commit f01847de14
6 changed files with 53 additions and 17 deletions

View file

@ -16,12 +16,14 @@
{ {
"jointName": "RightHand", "jointName": "RightHand",
"positionVar": "rightHandPosition", "positionVar": "rightHandPosition",
"rotationVar": "rightHandRotation" "rotationVar": "rightHandRotation",
"typeVar": "rightHandType"
}, },
{ {
"jointName": "LeftHand", "jointName": "LeftHand",
"positionVar": "leftHandPosition", "positionVar": "leftHandPosition",
"rotationVar": "leftHandRotation" "rotationVar": "leftHandRotation",
"typeVar": "leftHandType"
}, },
{ {
"jointName": "RightFoot", "jointName": "RightFoot",
@ -39,13 +41,13 @@
"jointName": "Neck", "jointName": "Neck",
"positionVar": "neckPosition", "positionVar": "neckPosition",
"rotationVar": "neckRotation", "rotationVar": "neckRotation",
"typeVar": "headAndNeckType" "typeVar": "neckType"
}, },
{ {
"jointName": "Head", "jointName": "Head",
"positionVar": "headPosition", "positionVar": "headPosition",
"rotationVar": "headRotation", "rotationVar": "headRotation",
"typeVar": "headAndNeckType" "typeVar": "headType"
} }
] ]
}, },
@ -63,7 +65,7 @@
"id": "spineLean", "id": "spineLean",
"type": "manipulator", "type": "manipulator",
"data": { "data": {
"alpha": 1.0, "alpha": 0.0,
"joints": [ "joints": [
{ "var": "lean", "jointName": "Spine" } { "var": "lean", "jointName": "Spine" }
] ]

View file

@ -337,16 +337,18 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds
// define a vertical capsule // define a vertical capsule
static float adebug = 1.0f; // adebug
const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters
const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters.
auto newBodySensorMatrix = deriveBodyFromHMDSensor(); auto newBodySensorMatrix = deriveBodyFromHMDSensor();
glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix);
if (!_straighteningLean && (capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { if (!_straighteningLean && (capsuleCheck(diff, adebug * STRAIGHTENING_LEAN_CAPSULE_LENGTH, adebug * STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) {
// begin homing toward derived body position. // begin homing toward derived body position.
_straighteningLean = true; _straighteningLean = true;
_straighteningLeanAlpha = 0.0f; _straighteningLeanAlpha = 0.0f;
adebug = 1000.0f; // adebug
} else if (_straighteningLean) { } else if (_straighteningLean) {

View file

@ -98,8 +98,14 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition)); target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
if (target.getType() != IKTarget::Type::Unknown) { if (target.getType() != IKTarget::Type::Unknown) {
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
target.setPose(animVars.lookup(targetVar.rotationVar, defaultPose.rot), glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
animVars.lookup(targetVar.positionVar, defaultPose.trans)); glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans);
if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) {
translation += _hipsOffset;
// HACK to test whether lifting idle hands will release the shoulders
translation.y += 0.10f;
}
target.setPose(rotation, translation);
target.setIndex(targetVar.jointIndex); target.setIndex(targetVar.jointIndex);
targets.push_back(target); targets.push_back(target);
if (targetVar.jointIndex > _maxTargetIndex) { if (targetVar.jointIndex > _maxTargetIndex) {
@ -125,6 +131,10 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
} }
} }
} }
static int adebug = 0; ++adebug; bool verbose = (0 == (adebug % 100));
if (verbose) {
std::cout << "adebug num targets = " << targets.size() << std::endl; // adebug
}
} }
void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets) { void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<IKTarget>& targets) {
@ -175,7 +185,8 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector<I
glm::vec3 leverArm = tipPosition - jointPosition; glm::vec3 leverArm = tipPosition - jointPosition;
glm::quat deltaRotation; glm::quat deltaRotation;
if (targetType == IKTarget::Type::RotationAndPosition) { if (targetType == IKTarget::Type::RotationAndPosition ||
targetType == IKTarget::Type::HipsRelativeRotationAndPosition) {
// compute the swing that would get get tip closer // compute the swing that would get get tip closer
glm::vec3 targetLine = target.getTranslation() - jointPosition; glm::vec3 targetLine = target.getTranslation() - jointPosition;
glm::vec3 axis = glm::cross(leverArm, targetLine); glm::vec3 axis = glm::cross(leverArm, targetLine);
@ -365,23 +376,28 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
solveWithCyclicCoordinateDescent(targets); solveWithCyclicCoordinateDescent(targets);
// compute the new target hips offset (for next frame) // compute the new target hips offset (for next frame)
// by looking for discrepancies between where a targeted endEffector is // by looking for discrepancies between where a targeted endEffector is
// and where it wants to be (after IK solutions are done) // and where it wants to be (after IK solutions are done)
glm::vec3 hmdHipsOffset(100.0f);
glm::vec3 newHipsOffset = Vectors::ZERO; glm::vec3 newHipsOffset = Vectors::ZERO;
for (auto& target: targets) { for (auto& target: targets) {
int targetIndex = target.getIndex(); int targetIndex = target.getIndex();
if (targetIndex == _headIndex && _headIndex != -1) { if (targetIndex == _headIndex && _headIndex != -1) {
// special handling for headTarget // special handling for headTarget
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans;
glm::vec3 over = under;
if (target.getType() == IKTarget::Type::RotationOnly) { if (target.getType() == IKTarget::Type::RotationOnly) {
over = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans; // we want to shift the hips to bring the underpose closer
} else if (target.getType() == IKTarget::Type::RotationAndPosition) { // to where the head happens to be (overpose)
over = target.getTranslation(); glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans;
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans;
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under);
} 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;
hmdHipsOffset = _hipsOffset + target.getTranslation() - actual;
} }
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (over - under);
} else if (target.getType() == IKTarget::Type::RotationAndPosition) { } else if (target.getType() == IKTarget::Type::RotationAndPosition) {
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans; glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans;
glm::vec3 targetPosition = target.getTranslation(); glm::vec3 targetPosition = target.getTranslation();
@ -392,6 +408,10 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
// 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.15f; const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.15f;
_hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE); _hipsOffset += (newHipsOffset - _hipsOffset) * (dt / HIPS_OFFSET_SLAVE_TIMESCALE);
//_hipsOffset *= 0.0f; // adebug
if (glm::length2(hmdHipsOffset) < 100.0f) {
_hipsOffset = hmdHipsOffset;
}
} }
} }
return _relativePoses; return _relativePoses;

View file

@ -25,6 +25,9 @@ void IKTarget::setType(int type) {
case (int)Type::HmdHead: case (int)Type::HmdHead:
_type = Type::HmdHead; _type = Type::HmdHead;
break; break;
case (int)Type::HipsRelativeRotationAndPosition:
_type = Type::HipsRelativeRotationAndPosition;
break;
default: default:
_type = Type::Unknown; _type = Type::Unknown;
} }

View file

@ -18,6 +18,7 @@ public:
RotationAndPosition, RotationAndPosition,
RotationOnly, RotationOnly,
HmdHead, HmdHead,
HipsRelativeRotationAndPosition,
Unknown, Unknown,
}; };

View file

@ -1058,9 +1058,11 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.set("headPosition", headPos); _animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot); _animVars.set("headRotation", headRot);
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationAndPosition); _animVars.set("headType", (int)IKTarget::Type::HmdHead);
_animVars.set("neckPosition", neckPos); _animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot); _animVars.set("neckRotation", neckRot);
//_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
} else { } else {
@ -1072,8 +1074,10 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.unset("headPosition"); _animVars.unset("headPosition");
_animVars.set("headRotation", realLocalHeadOrientation); _animVars.set("headRotation", realLocalHeadOrientation);
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly); _animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("headType", (int)IKTarget::Type::RotationOnly);
_animVars.unset("neckPosition"); _animVars.unset("neckPosition");
_animVars.unset("neckRotation"); _animVars.unset("neckRotation");
_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
} }
} else if (!_enableAnimGraph) { } else if (!_enableAnimGraph) {
@ -1131,16 +1135,20 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
if (params.isLeftEnabled) { if (params.isLeftEnabled) {
_animVars.set("leftHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.leftPosition); _animVars.set("leftHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.leftPosition);
_animVars.set("leftHandRotation", rootBindPose.rot * yFlipHACK * params.leftOrientation); _animVars.set("leftHandRotation", rootBindPose.rot * yFlipHACK * params.leftOrientation);
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
} else { } else {
_animVars.unset("leftHandPosition"); _animVars.unset("leftHandPosition");
_animVars.unset("leftHandRotation"); _animVars.unset("leftHandRotation");
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
} }
if (params.isRightEnabled) { if (params.isRightEnabled) {
_animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition); _animVars.set("rightHandPosition", rootBindPose.trans + rootBindPose.rot * yFlipHACK * params.rightPosition);
_animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation); _animVars.set("rightHandRotation", rootBindPose.rot * yFlipHACK * params.rightOrientation);
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
} else { } else {
_animVars.unset("rightHandPosition"); _animVars.unset("rightHandPosition");
_animVars.unset("rightHandRotation"); _animVars.unset("rightHandRotation");
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
} }
// set leftHand grab vars // set leftHand grab vars