ARCore untuk Jetpack XR dapat memberikan informasi tentang tangan pengguna yang terdeteksi, dan memberikan informasi pose untuk tangan dan sambungan terkaitnya. Data tangan ini dapat digunakan untuk melampirkan entitas dan model ke tangan pengguna, misalnya, menu alat:
Mendapatkan sesi
Akses informasi tangan melalui Session
Android XR. Lihat Memahami siklus proses Sesi untuk mendapatkan Session
.
Mengonfigurasi sesi
Pelacakan tangan tidak diaktifkan secara default pada sesi XR. Untuk menerima data tangan,
konfigurasi sesi dan tetapkan mode 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. */) }
Mengambil data tangan
Data tangan tersedia untuk tangan kiri dan kanan secara terpisah. Gunakan
state
setiap tangan untuk mengakses posisi pose setiap sambungan:
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) }
Tangan memiliki properti berikut:
trackingState
: apakah tangan dilacak atau tidak.handJoints
: peta sendi tangan ke pose. Pose sambungan tangan ditentukan oleh standar OpenXR.
Menggunakan data tangan di aplikasi Anda
Posisi sendi tangan pengguna dapat digunakan untuk menambatkan objek 3D ke tangan pengguna, misalnya, untuk melampirkan model ke telapak tangan kiri:
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))
Atau untuk melampirkan model ke ujung jari telunjuk tangan kanan Anda:
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))
Mendeteksi gestur tangan dasar
Gunakan pose sambungan di tangan untuk mendeteksi gestur tangan dasar. Lihat Konvensi sendi tangan untuk menentukan rentang pose sendi yang harus berada dalam pose tertentu agar dapat didaftarkan sebagai pose yang diberikan.
Misalnya, untuk mendeteksi gerakan mencubit dengan ibu jari dan jari telunjuk, gunakan jarak antara dua sambungan ujung jari:
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
Contoh gestur yang lebih rumit adalah gestur "berhenti". Dalam gestur ini, setiap jari harus direntangkan, yaitu setiap sendi di setiap jari harus mengarah ke arah yang sama:
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)
Perhatikan poin-poin berikut saat mengembangkan deteksi kustom untuk gestur tangan:
- Pengguna mungkin memiliki interpretasi yang berbeda untuk setiap gestur tertentu. Misalnya, beberapa orang mungkin menganggap gestur "berhenti" dilakukan dengan jari-jari terentang, sementara yang lain mungkin menganggap lebih intuitif jika jari-jari saling berdekatan.
- Beberapa gestur mungkin tidak nyaman untuk dilakukan. Gunakan gestur intuitif yang tidak membuat tangan pengguna tegang.
Menentukan tangan sekunder pengguna
Sistem Android menempatkan navigasi sistem di tangan utama pengguna, seperti yang ditentukan oleh pengguna dalam preferensi sistem. Gunakan tangan sekunder untuk gestur kustom Anda guna menghindari konflik dengan gestur navigasi sistem:
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™ dan logo OpenXR adalah merek dagang yang dimiliki oleh The Khronos Group Inc. dan terdaftar sebagai merek dagang di China, Uni Eropa, Jepang, dan Inggris Raya.