ARCore for Jetpack XR יכול לספק מידע על הידיים שזוהו אצל המשתמש, וגם מידע על התנוחה של הידיים והמפרקים שלהן. אפשר להשתמש בנתוני הידיים האלה כדי לצרף ישויות ומודלים לידיים של המשתמש, למשל תפריט כלים:
קבלת סשן
גישה למידע על הידיים דרך Session
Android XR. כדי לקבל Session
, אפשר לעיין במאמר בנושא הסבר על מחזור החיים של סשן.
הגדרת הסשן
מעקב אחר תנועות הידיים לא מופעל כברירת מחדל בסשנים של XR. כדי לקבל נתונים של הידיים, צריך להגדיר את הסשן ולהגדיר את המצב HandTrackingMode.BOTH
:
val newConfig = session.config.copy( handTracking = Config.HandTrackingMode.BOTH ) when (val result = session.configure(newConfig)) { is SessionConfigureConfigurationNotSupported -> TODO(/* Some combinations of configurations are not valid. Handle this failure case. */) is SessionConfigureSuccess -> TODO(/* Success! */) else -> TODO(/* A different unhandled exception was thrown. */) }
אחזור נתוני הידיים
נתוני הידיים זמינים בנפרד ליד ימין וליד שמאל. משתמשים ב-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.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.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.THUMB_TIP] ?: return false val thumbTipPose = session.scene.perceptionSpace.transformPoseTo(thumbTip, session.scene.activitySpace) val indexTip = handState.handJoints[HandJointType.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.INDEX_PROXIMAL, HandJointType.INDEX_TIP) && pointingInSameDirection(HandJointType.MIDDLE_PROXIMAL, HandJointType.MIDDLE_TIP) && pointingInSameDirection(HandJointType.RING_PROXIMAL, HandJointType.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. והם רשומים כסימן מסחרי בסין, באיחוד האירופי, ביפן ובבריטניה.