diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 5aab7813eb..02ffb903a1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -164,16 +164,30 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Rig::HandParameters handParams; + // compute interp factor between in body and out of body hand positions. + const float MIN_OUT_OF_BODY_DISTANCE = TRUNCATE_IK_CAPSULE_RADIUS - 0.1f; + const float MAX_OUT_OF_BODY_DISTANCE = TRUNCATE_IK_CAPSULE_RADIUS + 0.1f; + glm::vec3 capsuleStart = Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f); + glm::vec3 capsuleEnd = -Vectors::UNIT_Y * (TRUNCATE_IK_CAPSULE_LENGTH / 2.0f); + float outOfBodyAlpha = distanceFromCapsule(hmdPositionInRigSpace, capsuleStart, capsuleEnd, TRUNCATE_IK_CAPSULE_RADIUS); + outOfBodyAlpha = (glm::clamp(outOfBodyAlpha, MIN_OUT_OF_BODY_DISTANCE, MAX_OUT_OF_BODY_DISTANCE) - MIN_OUT_OF_BODY_DISTANCE) / + (MAX_OUT_OF_BODY_DISTANCE - MIN_OUT_OF_BODY_DISTANCE); + auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame(); if (leftPose.isValid()) { handParams.isLeftEnabled = true; handParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation(); handParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation(); - // truncate hand target - if (myAvatar->isOutOfBody() && qApp->isHMDMode()) { + // adjust hand position if head is out of body. + if (qApp->isHMDMode()) { + + // compute the out of body hand position. glm::vec3 offset = handParams.leftPosition - hmdPositionInRigSpace; - handParams.leftPosition = truncatedHMDPositionInRigSpace + offset; + glm::vec3 outOfBodyLeftPosition = truncatedHMDPositionInRigSpace + offset; + + // interpolate between in body and out of body hand position. + handParams.leftPosition = lerp(handParams.leftPosition, outOfBodyLeftPosition, outOfBodyAlpha); } } else { handParams.isLeftEnabled = false; @@ -185,10 +199,15 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation(); handParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation(); - // truncate hand target - if (myAvatar->isOutOfBody() && qApp->isHMDMode()) { + // adjust hand position if head is out of body. + if (qApp->isHMDMode()) { + + // compute the out of body hand position. glm::vec3 offset = handParams.rightPosition - hmdPositionInRigSpace; - handParams.rightPosition = truncatedHMDPositionInRigSpace + offset; + glm::vec3 outOfBodyRightPosition = truncatedHMDPositionInRigSpace + offset; + + // interpolate between in body and out of body hand position. + handParams.rightPosition = lerp(handParams.rightPosition, outOfBodyRightPosition, outOfBodyAlpha); } } else { handParams.isRightEnabled = false; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 9cf668f733..91623f1e83 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -596,6 +596,10 @@ float distanceFromLineSegment(const glm::vec3& point, const glm::vec3& segmentSt return glm::length(point - nearestPointOnLineSegment(point, segmentStart, segmentEnd)); } +float distanceFromCapsule(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd, float capsuleRadius) { + return distanceFromLineSegment(point, segmentStart, segmentEnd) - capsuleRadius; +} + bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius) { return distanceFromLineSegment(point, capsuleStart, capsuleEnd) < capsuleRadius; } @@ -604,7 +608,7 @@ glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsu glm::vec3 nearestPoint = nearestPointOnLineSegment(point, capsuleStart, capsuleEnd); glm::vec3 d = point - nearestPoint; float dLen = glm::length(d); - if (dLen > EPSILON) { + if (dLen < EPSILON) { return nearestPoint; // TODO: maybe we should pick a point actually on the surface... } else { return nearestPoint + d * (capsuleRadius / dLen); diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index 05ca415cac..47f069931d 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -162,6 +162,7 @@ private: glm::vec3 nearestPointOnLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd); float distanceFromLineSegment(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd); +float distanceFromCapsule(const glm::vec3& point, const glm::vec3& segmentStart, const glm::vec3& segmentEnd, float capsuleRadius); bool pointIsInsideCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius); glm::vec3 projectPointOntoCapsule(const glm::vec3& point, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius);