ARCore for Jetpack XR יכול לספק מידע על הידיים של המשתמש שזוהו, וגם מידע על התנוחה של הידיים והמפרקים שקשורים אליהן. אפשר להשתמש בנתוני הידיים האלה כדי לצרף ישויות ומודלים לידיים של המשתמש, למשל תפריט של כלי:
גישה לסשן
גישה למידע על הידיים דרך Jetpack XR Runtime Session,
שאפשר ליצור באפליקציה.
הגדרת הסשן
התכונה 'מעקב אחר תנועות הידיים' לא מופעלת כברירת מחדל בסשנים של XR. כדי לקבל נתונים של הידיים, צריך להגדיר את הסשן ולבחור את המצב של HandTrackingMode.BOTH:
val newConfig = session.config.copy( handTracking = Config.HandTrackingMode.BOTH ) when (val result = session.configure(newConfig)) { is SessionConfigureSuccess -> TODO(/* Success! */) else -> TODO(/* The session could not be configured. See SessionConfigureResult for possible causes. */) }
אחזור נתונים של הידיים
נתוני הידיים זמינים בנפרד ליד ימין וליד שמאל. משתמשים ב-state של כל יד כדי לגשת למיקומי התנוחה של כל מפרק:
Hand.left(session)?.state?.collect { handState -> // or Hand.right(session) // Hand state has been updated. // Use the state of hand joints to update an entity's position. renderPlanetAtHandPalm(handState) }
למאפיין הידיים יש את המאפיינים הבאים:
-
trackingState: האם היד במעקב או לא.
handJoints: מיפוי של מפרקי הידיים לתנוחות. תנוחות המפרקים של הידיים מוגדרות על ידי תקני OpenXR.
שימוש בנתוני הידיים באפליקציה
אפשר להשתמש במיקומים של מפרקי הידיים של המשתמש כדי לעגן אובייקטים תלת-ממדיים לידיים של המשתמש. לדוגמה, כדי לצרף מודל לכף היד השמאלית:
val palmPose = leftHandState.handJoints[HandJointType.HAND_JOINT_TYPE_PALM] ?: return // the down direction points in the same direction as the palm val angle = Vector3.angleBetween(palmPose.rotation * Vector3.Down, Vector3.Up) palmEntity.setEnabled(angle > Math.toRadians(40.0)) val transformedPose = session.scene.perceptionSpace.transformPoseTo( palmPose, session.scene.activitySpace, ) val newPosition = transformedPose.translation + transformedPose.down * 0.05f palmEntity.setPose(Pose(newPosition, transformedPose.rotation))
או כדי לצרף מודל לקצה האצבע המורה של יד ימין:
val tipPose = rightHandState.handJoints[HandJointType.HAND_JOINT_TYPE_INDEX_TIP] ?: return // the forward direction points towards the finger tip. val angle = Vector3.angleBetween(tipPose.rotation * Vector3.Forward, Vector3.Up) indexFingerEntity.setEnabled(angle > Math.toRadians(40.0)) val transformedPose = session.scene.perceptionSpace.transformPoseTo( tipPose, session.scene.activitySpace, ) val position = transformedPose.translation + transformedPose.forward * 0.03f val rotation = Quaternion.fromLookTowards(transformedPose.up, Vector3.Up) indexFingerEntity.setPose(Pose(position, rotation))
זיהוי תנועות ידיים בסיסיות
השיטה הזו משתמשת בתנוחות של המפרקים ביד כדי לזהות תנועות ידיים בסיסיות. כדי לקבוע באיזה טווח של תנוחות המפרקים צריכים להיות כדי להירשם כתנוחה מסוימת, אפשר לעיין במוסכמות של מפרקי הידיים.
לדוגמה, כדי לזהות צביטה באגודל ובאצבע, משתמשים במרחק בין שני מפרקי הקצה:
val thumbTip = handState.handJoints[HandJointType.HAND_JOINT_TYPE_THUMB_TIP] ?: return false val thumbTipPose = session.scene.perceptionSpace.transformPoseTo(thumbTip, session.scene.activitySpace) val indexTip = handState.handJoints[HandJointType.HAND_JOINT_TYPE_INDEX_TIP] ?: return false val indexTipPose = session.scene.perceptionSpace.transformPoseTo(indexTip, session.scene.activitySpace) return Vector3.distance(thumbTipPose.translation, indexTipPose.translation) < 0.05
דוגמה לתנועה מורכבת יותר היא תנועת ה "עצירה". במחוות הזו, כל האצבעות צריכות להיות ישרות, כלומר כל מפרק בכל אצבע צריך להצביע בערך לאותו כיוון:
val threshold = toRadians(angleInDegrees = 30f) fun pointingInSameDirection(joint1: HandJointType, joint2: HandJointType): Boolean { val forward1 = handState.handJoints[joint1]?.forward ?: return false val forward2 = handState.handJoints[joint2]?.forward ?: return false return Vector3.angleBetween(forward1, forward2) < threshold } return pointingInSameDirection(HandJointType.HAND_JOINT_TYPE_INDEX_PROXIMAL, HandJointType.HAND_JOINT_TYPE_INDEX_TIP) && pointingInSameDirection(HandJointType.HAND_JOINT_TYPE_MIDDLE_PROXIMAL, HandJointType.HAND_JOINT_TYPE_MIDDLE_TIP) && pointingInSameDirection(HandJointType.HAND_JOINT_TYPE_RING_PROXIMAL, HandJointType.HAND_JOINT_TYPE_RING_TIP)
כשמפתחים זיהוי מותאם אישית של תנועות ידיים, חשוב לזכור את הנקודות הבאות:
- יכול להיות שלמשתמשים תהיה פרשנות שונה של כל תנועה נתונה. לדוגמה, יש אנשים שחושבים שמחווה של עצירה היא כשהאצבעות פרושות, ויש אנשים שחושבים שזה יותר אינטואיטיבי כשהאצבעות צמודות.
- יכול להיות שיהיה קשה לשמור על חלק מהתנועות. להשתמש בתנועות אינטואיטיביות שלא מאמצות את הידיים של המשתמש.
קביעת היד המשנית של המשתמש
מערכת Android ממקמת את הניווט במערכת בצד של היד העיקרית של המשתמש, כפי שהוגדר על ידי המשתמש בהעדפות המערכת. כדי למנוע התנגשויות עם תנועות הניווט במערכת, משתמשים ביד המשנית לתנועות המותאמות אישית:
val handedness = Hand.getPrimaryHandSide(activity.contentResolver) val secondaryHand = if (handedness == Hand.HandSide.LEFT) Hand.right(session) else Hand.left(session) val handState = secondaryHand?.state ?: return detectGesture(handState)
OpenXR™ והלוגו של OpenXR הם סימנים מסחריים בבעלות The Khronos Group Inc. והם רשומים כסימן מסחרי בסין, באיחוד האירופי, ביפן ובבריטניה.