ARCore cho Jetpack XR có thể cung cấp thông tin về bàn tay được phát hiện của người dùng, đồng thời cung cấp thông tin về tư thế cho bàn tay và các khớp liên quan. Dữ liệu về bàn tay này có thể được dùng để đính kèm các thực thể và mô hình vào bàn tay của người dùng, ví dụ: trình đơn công cụ:
Lấy một phiên
Truy cập thông tin về bàn tay thông qua Session
Android XR. Hãy xem phần Tìm hiểu vòng đời của Phiên để lấy Session
.
Định cấu hình phiên
Theo mặc định, tính năng theo dõi cử chỉ tay không được bật trên các phiên XR. Để nhận dữ liệu về bàn tay, hãy định cấu hình phiên:
val newConfig = session.config.copy( handTracking = Config.HandTrackingMode.Enabled ) when (val result = session.configure(newConfig)) { is SessionConfigureConfigurationNotSupported -> TODO(/* Some combinations of configurations are not valid. Handle this failure case. */) is SessionConfigurePermissionsNotGranted -> TODO(/* The required permissions in result.permissions have not been granted. */) is SessionConfigureSuccess -> TODO(/* Success! */) }
Truy xuất dữ liệu về bàn tay
Dữ liệu về tay có sẵn riêng cho tay trái và tay phải. Sử dụng state
của mỗi tay để truy cập vào các vị trí tạo dáng cho từng khớp:
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) }
Kim có các thuộc tính sau:
isActive
: liệu tay có đang được theo dõi hay không.handJoints
: bản đồ các khớp tay đến tư thế. Tư thế khớp tay được chỉ định theo các tiêu chuẩn OpenXR.
Sử dụng dữ liệu về cử chỉ tay trong ứng dụng
Bạn có thể sử dụng vị trí của các khớp tay của người dùng để neo các đối tượng 3D vào tay của người dùng, chẳng hạn như để đính kèm một mô hình vào lòng bàn tay trái:
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.setHidden(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))
Hoặc để đính kèm một mô hình vào đầu ngón trỏ của tay phải:
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.setHidden(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))
Phát hiện cử chỉ cơ bản của tay
Sử dụng tư thế của các khớp trong bàn tay để phát hiện các cử chỉ cơ bản của bàn tay. Hãy tham khảo Quy ước về các khớp tay để xác định phạm vi tư thế mà các khớp phải ở để đăng ký dưới dạng một tư thế nhất định.
Ví dụ: để phát hiện thao tác chụm bằng ngón cái và ngón trỏ, hãy sử dụng khoảng cách giữa hai khớp đầu ngón tay:
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
Ví dụ về một cử chỉ phức tạp hơn là cử chỉ "dừng". Trong cử chỉ này, mỗi ngón tay phải được duỗi ra, tức là mỗi khớp trong mỗi ngón tay phải hướng về cùng một hướng:
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)
Hãy lưu ý những điểm sau khi phát triển tính năng phát hiện tuỳ chỉnh cho cử chỉ bằng tay:
- Người dùng có thể có cách diễn giải khác nhau về bất kỳ cử chỉ nào. Ví dụ: một số người có thể xem xét cử chỉ "dừng" là các ngón tay mở rộng, trong khi một số người khác có thể thấy trực quan hơn khi các ngón tay khép lại với nhau.
- Một số cử chỉ có thể gây khó chịu khi duy trì. Sử dụng các cử chỉ trực quan không gây căng thẳng cho tay người dùng.
Xác định kim phụ của người dùng
Hệ thống Android đặt thao tác điều hướng hệ thống ở tay chính của người dùng, như người dùng chỉ định trong phần lựa chọn ưu tiên của hệ thống. Sử dụng kim phụ cho các cử chỉ tuỳ chỉnh để tránh xung đột với cử chỉ điều hướng của hệ thống:
val handedness = Hand.getHandedness(activity.contentResolver) val secondaryHand = if (handedness == Hand.Handedness.LEFT) Hand.right(session) else Hand.left(session) val handState = secondaryHand?.state ?: return detectGesture(handState)