Improved shoulder calibration using hard-coded measured shoulder width

This commit is contained in:
Anthony J. Thibault 2017-07-25 15:24:09 -07:00
parent 33a1d6e225
commit c81875a280
4 changed files with 67 additions and 11 deletions

View file

@ -1862,15 +1862,40 @@ void AnimInverseKinematics::preconditionRelativePosesToAvoidLimbLock(const AnimC
// overwrites _relativePoses with secondary poses.
void AnimInverseKinematics::setSecondaryTargets(const AnimContext& context) {
if (_secondaryTargetsInRigFrame.empty()) {
return;
}
// shoulder joint should look-at position of arm joint.
const int leftArmIndex = _skeleton->nameToJointIndex("LeftArm");
const int rightArmIndex = _skeleton->nameToJointIndex("RightArm");
AnimPose rigToGeometryPose = AnimPose(glm::inverse(context.getGeometryToRigMatrix()));
for (auto& iter : _secondaryTargetsInRigFrame) {
AnimPose absPose = rigToGeometryPose * iter.second;
absPose.scale() = glm::vec3(1.0f);
AnimPose parentAbsPose;
int parentIndex = _skeleton->getParentIndex(iter.first);
if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
}
// if parent should "look-at" child joint position.
if (iter.first == leftArmIndex || iter.first == rightArmIndex) {
AnimPose grandParentAbsPose;
int grandParentIndex = _skeleton->getParentIndex(parentIndex);
if (parentIndex >= 0) {
grandParentAbsPose = _skeleton->getAbsolutePose(grandParentIndex, _relativePoses);
}
// the shoulder should rotate toward the arm joint via "look-at" constraint
parentAbsPose = boneLookAt(absPose.trans(), parentAbsPose);
_relativePoses[parentIndex] = grandParentAbsPose.inverse() * parentAbsPose;
}
// AJT: for now ignore translation on secondary poses.
glm::vec3 origTrans = _relativePoses[iter.first].trans();
_relativePoses[iter.first] = parentAbsPose.inverse() * absPose;

View file

@ -96,3 +96,14 @@ float accumulateTime(float startFrame, float endFrame, float timeScale, float cu
return frame;
}
// rotate bone's y-axis with target.
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone) {
glm::vec3 u, v, w;
generateBasisVectors(target - bone.trans(), bone.rot() * Vectors::UNIT_X, u, v, w);
glm::mat4 lookAt(glm::vec4(v, 0.0f),
glm::vec4(u, 0.0f),
// AJT: TODO REVISIT THIS, this could be -w.
glm::vec4(glm::normalize(glm::cross(v, u)), 0.0f),
glm::vec4(bone.trans(), 1.0f));
return AnimPose(lookAt);
}

View file

@ -31,4 +31,6 @@ inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
return glm::normalize(glm::lerp(a, bTemp, alpha));
}
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
#endif

View file

@ -644,17 +644,8 @@ void ViveControllerManager::InputDevice::updateCalibratedLimbs() {
_poseStateMap[controller::RIGHT_FOOT] = addOffsetToPuckPose(controller::RIGHT_FOOT);
_poseStateMap[controller::HIPS] = addOffsetToPuckPose(controller::HIPS);
_poseStateMap[controller::SPINE2] = addOffsetToPuckPose(controller::SPINE2);
controller::Pose rightArmPose = addOffsetToPuckPose(controller::RIGHT_ARM);
_poseStateMap[controller::RIGHT_ARM] = rightArmPose;
if (rightArmPose.isValid()) {
// AJT: TODO: compute rotation for RIGHT_SHOULDER AS WELL.
}
controller::Pose leftArmPose = addOffsetToPuckPose(controller::LEFT_ARM);
_poseStateMap[controller::LEFT_ARM] = leftArmPose;
if (leftArmPose.isValid()) {
// AJT: TODO: compute rotation for LEFT_SHOULDER AS WELL.
}
_poseStateMap[controller::RIGHT_ARM] = addOffsetToPuckPose(controller::RIGHT_ARM);
_poseStateMap[controller::LEFT_ARM] = addOffsetToPuckPose(controller::LEFT_ARM);
if (_overrideHead) {
_poseStateMap[controller::HEAD] = addOffsetToPuckPose(controller::HEAD);
@ -1146,6 +1137,25 @@ static glm::vec3 computeUserShoulderPositionFromHistory(const glm::mat4& headMat
return transformPoint(headMat, center);
}
// y axis comes out of puck usb port/green light
// -z axis comes out of puck center/vive logo
static glm::vec3 computeUserShoulderPositionFromMeasurements(const glm::mat4& headMat, const controller::Pose& armPuck, bool isLeftHand) {
// AJT: TODO measurments are hard coded!
const float ARM_CIRC = 0.33f; // 13 inches
const float SHOULDER_SPAN = 0.4826; // 19 inches
float armRadius = ARM_CIRC / TWO_PI;
float sign = isLeftHand ? 1.0f : -1.0f;
float localArmX = sign * SHOULDER_SPAN / 2.0f;
controller::Pose localPuck = armPuck.transform(glm::inverse(headMat));
glm::mat4 localPuckMat = localPuck.getMatrix();
glm::vec3 localArmCenter = extractTranslation(localPuckMat) + armRadius * transformVectorFast(localPuckMat, Vectors::UNIT_Z);
return transformPoint(headMat, glm::vec3(localArmX, localArmCenter.y, localArmCenter.z));
}
void ViveControllerManager::InputDevice::calibrateShoulders(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
int firstShoulderIndex, int secondShoulderIndex) {
const PuckPosePair& firstShoulder = _validTrackedObjects[firstShoulderIndex];
@ -1160,13 +1170,18 @@ void ViveControllerManager::InputDevice::calibrateShoulders(const glm::mat4& def
glm::mat4 userRefRightArm = refRightArm;
glm::mat4 headMat = defaultToReferenceMat * inputCalibration.defaultHeadMat;
/* AJT: TODO REMOVE
userRefLeftArm[3] = glm::vec4(computeUserShoulderPositionFromHistory(headMat, _leftControllerHistory), 1.0f);
userRefRightArm[3] = glm::vec4(computeUserShoulderPositionFromHistory(headMat, _rightControllerHistory), 1.0f);
*/
if (firstShoulderPose.translation.x < secondShoulderPose.translation.x) {
_jointToPuckMap[controller::LEFT_ARM] = firstShoulder.first;
_jointToPuckMap[controller::RIGHT_ARM] = secondShoulder.first;
userRefLeftArm[3] = glm::vec4(computeUserShoulderPositionFromMeasurements(headMat, firstShoulderPose, true), 1.0f);
userRefRightArm[3] = glm::vec4(computeUserShoulderPositionFromMeasurements(headMat, secondShoulderPose, false), 1.0f);
// compute the post offset from the userRefArm
_pucksPostOffset[firstShoulder.first] = computeOffset(Matrices::IDENTITY, userRefLeftArm, firstShoulderPose);
_pucksPostOffset[secondShoulder.first] = computeOffset(Matrices::IDENTITY, userRefRightArm, secondShoulderPose);
@ -1179,6 +1194,9 @@ void ViveControllerManager::InputDevice::calibrateShoulders(const glm::mat4& def
_jointToPuckMap[controller::LEFT_ARM] = secondShoulder.first;
_jointToPuckMap[controller::RIGHT_ARM] = firstShoulder.first;
userRefLeftArm[3] = glm::vec4(computeUserShoulderPositionFromMeasurements(headMat, secondShoulderPose, true), 1.0f);
userRefRightArm[3] = glm::vec4(computeUserShoulderPositionFromMeasurements(headMat, firstShoulderPose, false), 1.0f);
// compute the post offset from the userRefArm
_pucksPostOffset[secondShoulder.first] = computeOffset(Matrices::IDENTITY, userRefLeftArm, secondShoulderPose);
_pucksPostOffset[firstShoulder.first] = computeOffset(Matrices::IDENTITY, userRefRightArm, firstShoulderPose);