Jetpack XR için ARCore'u kullanarak ellerinizle çalışma

Jetpack XR için ARCore, kullanıcının algılanan elleri hakkında bilgi sağlayabilir ve eller ile ilişkili eklemler için poz bilgisi verir. Bu el verileri, kullanıcının ellerine öğe ve model eklemek için kullanılabilir. Örneğin, bir araç menüsü:

Oturum alma

Android XR Session ile el bilgilerine erişme Session almak için Oturumun yaşam döngüsünü anlama başlıklı makaleyi inceleyin.

Oturumu yapılandırma

El takibi, XR oturumlarında varsayılan olarak etkin değildir. El verilerini almak için oturumu yapılandırın ve HandTrackingMode.BOTH modunu ayarlayın:

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. */)
}

El verilerini alma

El verileri, sol ve sağ eller için ayrı ayrı kullanılabilir. Her eklemin pozisyonlarına erişmek için her elin state simgesini kullanın:

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)
}

Eller aşağıdaki özelliklere sahiptir:

  • trackingState: Elin takip edilip edilmediği.
  • handJoints: El eklemlerinin pozlarla eşlendiği bir harita. El eklemi pozları, OpenXR standartları ile belirtilir.

Uygulamanızda el verilerini kullanma

Kullanıcının el eklemlerinin konumları, 3D nesneleri kullanıcının ellerine sabitlemek için kullanılabilir. Örneğin, bir modeli sol avuca eklemek için:

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))

Dilerseniz modeli sağ elinizin işaret parmağı ucuna da ekleyebilirsiniz:

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))

Temel el hareketlerini algılama

Temel el hareketlerini algılamak için eldeki eklemlerin pozlarını kullanır. Eklemlerin belirli bir poz olarak kaydedilmesi için hangi poz aralığında olması gerektiğini belirlemek üzere El eklemlerinin kuralları'na bakın.

Örneğin, başparmak ve işaret parmağıyla yapılan bir tutma hareketini algılamak için iki parmak ucu eklemi arasındaki mesafeyi kullanın:

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

Daha karmaşık bir hareket örneği "durdurma" hareketidir. Bu harekette her parmak uzatılmalı, yani her parmaktaki her eklem yaklaşık olarak aynı yöne bakmalıdır:

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)

El hareketleri için özel algılama geliştirirken aşağıdaki noktaları aklınızda bulundurun:

  • Kullanıcılar, belirli bir hareketi farklı şekilde yorumlayabilir. Örneğin, bazıları "dur" hareketinde parmakların açık olmasını tercih ederken bazıları parmakların kapalı olmasını daha sezgisel bulabilir.
  • Bazı hareketleri sürdürmek rahatsız edici olabilir. Kullanıcının ellerini yormayan sezgisel hareketler kullanın.

Kullanıcının ikincil elini belirleme

Android sistemi, sistem tercihlerinde kullanıcının belirttiği şekilde sistem gezinmesini kullanıcının birincil eline yerleştirir. Sistem gezinme hareketleriyle çakışmayı önlemek için özel hareketlerinizde ikincil elinizi kullanın:

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™ ve OpenXR logosu, The Khronos Group Inc. şirketinin ticari markalarıdır ve Çin, Avrupa Birliği, Japonya ve Birleşik Krallık'ta ticari marka olarak tescillidir.