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 và cung cấp thông tin về tư thế cho bàn tay và các khớp liên quan. Dữ liệu bàn tay này có thể 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ụ: một 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 một 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 bàn tay, hãy định cấu hình phiên và đặt chế độ 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. */) }
Truy xuất dữ liệu bàn tay
Dữ liệu bàn tay có sẵn riêng cho tay trái và tay phải. Sử dụng state
của mỗi bàn tay để truy cập vào vị trí tư thế của 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) }
Bàn tay có các thuộc tính sau:
trackingState
: liệu bàn tay có đang được theo dõi hay không.handJoints
: bản đồ các khớp bàn tay đến tư thế. Tư thế khớp bàn tay được chỉ định theo các tiêu chuẩn OpenXR.
Sử dụng dữ liệu bàn tay trong ứng dụng
Bạn có thể dùng vị trí của các khớp bàn tay của người dùng để neo các đối tượng 3D vào bàn 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.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))
Hoặc để gắn một mô hình vào đầu ngón trỏ của bàn 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.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))
Phát hiện cử chỉ cơ bản của bàn tay
Sử dụng tư thế của các khớp trong bàn tay để phát hiện cử chỉ cơ bản của bàn tay. Tham khảo Quy ước về các khớp bàn tay để xác định phạm vi tư thế mà các khớp nên ở trong đó để đăng ký dưới dạng một tư thế nhất định.
Ví dụ: để phát hiện cử chỉ chụm ngón cái và ngón trỏ, hãy 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 duỗi thẳng, tức là mỗi khớp ở mỗi ngón tay phải chỉ theo 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 cử chỉ tuỳ chỉnh:
- Người dùng có thể diễn giải một cử chỉ bất kỳ theo cách khác. Ví dụ: một số người có thể coi cử chỉ "dừng lại" là cử chỉ xoè các ngón tay ra, trong khi những người khác có thể thấy cử chỉ khép các ngón tay lại trực quan hơn.
- 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 mà không gây mỏi tay cho người dùng.
Xác định tay phụ của người dùng
Hệ thống Android đặt chế độ thao tác bằng cử chỉ trên tay chính của người dùng, theo chỉ định của người dùng trong phần lựa chọn ưu tiên của hệ thống. Sử dụng tay phụ cho các cử chỉ tuỳ chỉnh để tránh xung đột với cử chỉ điều hướng hệ thống:
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™ và biểu trưng OpenXR là các nhãn hiệu thuộc sở hữu của The Khronos Group Inc. và được đăng ký làm nhãn hiệu ở Trung Quốc, Liên minh Châu Âu, Nhật Bản và Vương quốc Anh.