کار کردن با دست‌ها بااستفاده از ARCore برای Jetpack XR

دستگاه‌های XR قابل‌اعمال
این راهنمایی به شما کمک می‌کند برای این نوع دستگاه‌های واقعیت گسترده تجربه بسازید.
هدست‌های واقعیت گسترده
عینک واقعیت گسترده سیمی

‫ARCore برای Jetpack XR می‌تواند اطلاعاتی درباره دست‌های شناسایی‌شده کاربر ارائه دهد و اطلاعات وضعیت دست‌ها و مفاصل مرتبط با آن‌ها را ارائه می‌دهد. از این داده‌های دست می‌توان برای پیوست کردن نهادها و مدل‌ها به دست‌های کاربر استفاده کرد، برای مثال، منو ابزار:

دسترسی به جلسه

ازطریق Jetpack XR Runtime Session به اطلاعات دسترسی پیدا کنید، که برنامه شما می‌تواند ایجاد کند.

پیکربندی جلسه

ردیابی دست به‌طور پیش‌فرض در جلسات XR فعال نیست. برای دریافت داده‌های دست، جلسه را پیکربندی کنید و حالت HandTrackingMode.BOTH را تنظیم کنید:

val newConfig = Config.Builder(session.config)
    .setHandTracking(HandTrackingMode.BOTH)
    .build()
when (val result = session.configure(newConfig)) {
    is SessionConfigureSuccess -> TODO(/* Success! */)
    else ->
        TODO(/* The session could not be configured. See SessionConfigureResult for possible causes. */)
}

بازیابی داده‌های دست

داده‌های دست به‌صورت جداگانه برای دست چپ و راست دردسترس است. از 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 == HandSide.LEFT) Hand.right(session) else Hand.left(session)
detectGesture(secondaryHand.state)


‫OpenXR™‎ و نشان‌واره OpenXR علامت‌های تجاری متعلق به شرکت The Khronos Group Inc. ‎ هستند و به‌عنوان علامت تجاری در چین، اتحادیه اروپا، ژاپن، و پادشاهی متحد ثبت شده‌اند.