Merge pull request #14230 from amantley/shoulderSpaceFix

Hand Azimuth improvement
This commit is contained in:
Jeff Clinton 2018-11-12 16:00:26 -08:00 committed by GitHub
commit ab8ba2daad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 21 deletions

View file

@ -538,17 +538,25 @@ void MyAvatar::update(float deltaTime) {
// put the average hand azimuth into sensor space. // put the average hand azimuth into sensor space.
// then mix it with head facing direction to determine rotation recenter // then mix it with head facing direction to determine rotation recenter
if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2");
glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && !(spine2Index < 0)) {
// use the spine for the azimuth origin.
glm::quat spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index);
glm::vec3 handHipAzimuthAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y);
glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), handHipAzimuthAvatarSpace);
glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); glm::mat4 sensorToWorldMat = getSensorToWorldMatrix();
glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat);
glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace);
glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f);
if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) {
normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z));
glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH);
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau);
} else {
// use head facing if the chest arms vector is up or down.
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau);
} }
glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH);
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau);
} else { } else {
_headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau); _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau);
} }
@ -979,35 +987,48 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
} }
// Find the vector halfway between the hip to hand azimuth vectors // Find the vector halfway between the hip to hand azimuth vectors
// This midpoint hand azimuth is in Avatar space // This midpoint hand azimuth is in Spine2 space
glm::vec2 MyAvatar::computeHandAzimuth() const { glm::vec2 MyAvatar::computeHandAzimuth() const {
controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose leftHandPoseAvatarSpace = getLeftHandPose();
controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose();
controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD);
const float HALFWAY = 0.50f; const float HALFWAY = 0.50f;
glm::vec2 latestHipToHandController = _hipToHandController; glm::vec2 latestHipToHandController = _hipToHandController;
if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2");
if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid() && !(spine2Index < 0)) {
glm::vec3 spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index);
glm::quat spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index);
glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position;
glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - spine2Position;
glm::vec3 rightHandSpine2Space = glm::inverse(spine2Rotation) * rightHandOffset;
glm::vec3 leftHandSpine2Space = glm::inverse(spine2Rotation) * leftHandOffset;
// we need the old azimuth reading to prevent flipping the facing direction 180 // we need the old azimuth reading to prevent flipping the facing direction 180
// in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart.
glm::vec2 oldAzimuthReading = _hipToHandController; glm::vec2 oldAzimuthReading = _hipToHandController;
if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { if ((glm::length(glm::vec2(rightHandSpine2Space.x, rightHandSpine2Space.z)) > 0.0f) && (glm::length(glm::vec2(leftHandSpine2Space.x, leftHandSpine2Space.z)) > 0.0f)) {
latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandSpine2Space.x, rightHandSpine2Space.z)), glm::normalize(glm::vec2(leftHandSpine2Space.x, leftHandSpine2Space.z)), HALFWAY);
} else { } else {
latestHipToHandController = glm::vec2(0.0f, -1.0f); latestHipToHandController = glm::vec2(0.0f, 1.0f);
} }
glm::vec3 headLookAtAvatarSpace = transformVectorFast(headPoseAvatarSpace.getMatrix(), glm::vec3(0.0f, 0.0f, 1.0f)); glm::vec3 headLookAtAvatarSpace = transformVectorFast(headPoseAvatarSpace.getMatrix(), glm::vec3(0.0f, 0.0f, 1.0f));
glm::vec2 headAzimuthAvatarSpace = glm::vec2(headLookAtAvatarSpace.x, headLookAtAvatarSpace.z); glm::vec3 headLookAtSpine2Space = glm::inverse(spine2Rotation) * headLookAtAvatarSpace;
if (glm::length(headAzimuthAvatarSpace) > 0.0f) {
headAzimuthAvatarSpace = glm::normalize(headAzimuthAvatarSpace); glm::vec2 headAzimuthSpine2Space = glm::vec2(headLookAtSpine2Space.x, headLookAtSpine2Space.z);
if (glm::length(headAzimuthSpine2Space) > 0.0f) {
headAzimuthSpine2Space = glm::normalize(headAzimuthSpine2Space);
} else { } else {
headAzimuthAvatarSpace = -latestHipToHandController; headAzimuthSpine2Space = -latestHipToHandController;
} }
// check the angular distance from forward and back // check the angular distance from forward and back
float cosForwardAngle = glm::dot(latestHipToHandController, oldAzimuthReading); float cosForwardAngle = glm::dot(latestHipToHandController, oldAzimuthReading);
float cosHeadShoulder = glm::dot(-latestHipToHandController, headAzimuthAvatarSpace); float cosHeadShoulder = glm::dot(-latestHipToHandController, headAzimuthSpine2Space);
// if we are now closer to the 180 flip of the previous chest forward // if we are now closer to the 180 flip of the previous chest forward
// then we negate our computed latestHipToHandController to keep the chest from flipping. // then we negate our computed latestHipToHandController to keep the chest from flipping.
// also check the head to shoulder azimuth difference if we negate. // also check the head to shoulder azimuth difference if we negate.
@ -3518,19 +3539,33 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
} }
glm::mat4 MyAvatar::getSpine2RotationRigSpace() const { glm::mat4 MyAvatar::getSpine2RotationRigSpace() const {
int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2");
glm::quat spine2Rot = Quaternions::IDENTITY;
if (!(spine2Index < 0)) {
// use the spine for the azimuth origin.
spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index);
}
glm::vec3 spine2UpAvatarSpace = spine2Rot * glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 spine2FwdAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y);
// static const glm::quat RIG_CHANGE_OF_BASIS = Quaternions::Y_180; // static const glm::quat RIG_CHANGE_OF_BASIS = Quaternions::Y_180;
// RIG_CHANGE_OF_BASIS * AVATAR_TO_RIG_ROTATION * inverse(RIG_CHANGE_OF_BASIS) = Quaternions::Y_180; //avatar Space; // RIG_CHANGE_OF_BASIS * AVATAR_TO_RIG_ROTATION * inverse(RIG_CHANGE_OF_BASIS) = Quaternions::Y_180; //avatar Space;
const glm::quat AVATAR_TO_RIG_ROTATION = Quaternions::Y_180; const glm::quat AVATAR_TO_RIG_ROTATION = Quaternions::Y_180;
glm::vec3 hipToHandRigSpace = AVATAR_TO_RIG_ROTATION * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); glm::vec3 spine2UpRigSpace = AVATAR_TO_RIG_ROTATION * spine2UpAvatarSpace;
glm::vec3 spine2FwdRigSpace = AVATAR_TO_RIG_ROTATION * spine2FwdAvatarSpace;
glm::vec3 u, v, w; glm::vec3 u, v, w;
if (glm::length(hipToHandRigSpace) > 0.0f) { if (glm::length(spine2FwdRigSpace) > 0.0f) {
hipToHandRigSpace = glm::normalize(hipToHandRigSpace); spine2FwdRigSpace = glm::normalize(spine2FwdRigSpace);
} else { } else {
hipToHandRigSpace = glm::vec3(0.0f, 0.0f, 1.0f); spine2FwdRigSpace = glm::vec3(0.0f, 0.0f, 1.0f);
} }
generateBasisVectors(glm::vec3(0.0f,1.0f,0.0f), hipToHandRigSpace, u, v, w); if (glm::length(spine2UpRigSpace) > 0.0f) {
spine2UpRigSpace = glm::normalize(spine2UpRigSpace);
} else {
spine2UpRigSpace = glm::vec3(0.0f, 1.0f, 0.0f);
}
generateBasisVectors(spine2UpRigSpace, spine2FwdRigSpace, u, v, w);
glm::mat4 spine2RigSpace(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f)); glm::mat4 spine2RigSpace(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f));
return spine2RigSpace; return spine2RigSpace;
} }

View file

@ -1731,7 +1731,7 @@ private:
glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space) glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space)
glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f }; glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f };
glm::vec2 _hipToHandController { 0.0f, -1.0f }; // spine2 facing vector in xz plane (avatar space) glm::vec2 _hipToHandController { 0.0f, 1.0f }; // spine2 facing vector in xz plane (spine2 space)
float _currentStandingHeight { 0.0f }; float _currentStandingHeight { 0.0f };
bool _resetMode { true }; bool _resetMode { true };

View file

@ -233,6 +233,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() &&
!(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) {
const float SPINE2_ROTATION_FILTER = 0.5f;
AnimPose currentSpine2Pose; AnimPose currentSpine2Pose;
AnimPose currentHeadPose; AnimPose currentHeadPose;
AnimPose currentHipsPose; AnimPose currentHipsPose;
@ -252,7 +253,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
} }
generateBasisVectors(up, fwd, u, v, w); generateBasisVectors(up, fwd, u, v, w);
AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f))); AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f)));
currentSpine2Pose.rot() = newSpinePose.rot(); currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), SPINE2_ROTATION_FILTER);
params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose; params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose;
params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated;
} }