Jetpack XR-এর জন্য ARCore ব্যবহার করে হাত দিয়ে কাজ করুন

জেটপ্যাক এক্সআর-এর জন্য ARCore ব্যবহারকারীর শনাক্ত করা হাত সম্পর্কে তথ্য প্রদান করতে পারে এবং হাত এবং তাদের সংযুক্ত জয়েন্টগুলির জন্য পোজ তথ্য দেয়। এই হ্যান্ড ডেটা ব্যবহারকারীর হাতে সত্তা এবং মডেল সংযুক্ত করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, একটি টুল মেনু:

একটি অধিবেশন প্রাপ্ত

একটি Android XR Session মাধ্যমে হাতের তথ্য অ্যাক্সেস করুন। একটি Session পাওয়ার জন্য একটি সেশনের জীবনচক্র বুঝতে দেখুন।

সেশন কনফিগার করুন

এক্সআর সেশনে ডিফল্টরূপে হ্যান্ড ট্র্যাকিং সক্ষম হয় না। হ্যান্ড ডেটা পেতে, সেশনটি কনফিগার করুন:

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

হাতের ডেটা পুনরুদ্ধার করুন

হাতের ডেটা বাম এবং ডান হাতের জন্য আলাদাভাবে উপলব্ধ। প্রতিটি জয়েন্টের জন্য পোজ পজিশন অ্যাক্সেস করতে প্রতিটি হাতের 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)
}

হাতের নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • isActive : হাত ট্র্যাক করা হচ্ছে কিনা।
  • handJoints : পোজ করার জন্য হাতের জয়েন্টগুলির একটি মানচিত্র। হাতের জয়েন্টের ভঙ্গি OpenXR মান দ্বারা নির্দিষ্ট করা হয়।

আপনার অ্যাপে হাতের ডেটা ব্যবহার করুন

ব্যবহারকারীর হাতের জয়েন্টগুলির অবস্থানগুলি ব্যবহারকারীর হাতে 3D বস্তুগুলিকে নোঙ্গর করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, বাম হাতের তালুতে একটি মডেল সংযুক্ত করতে:

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

অথবা আপনার ডান হাতের তর্জনীর ডগায় একটি মডেল সংযুক্ত করতে:

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

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করুন

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করতে হাতের জয়েন্টগুলির ভঙ্গি ব্যবহার করুন। প্রদত্ত ভঙ্গি হিসাবে নিবন্ধন করার জন্য জয়েন্টগুলি কোন সীমার ভঙ্গিতে থাকা উচিত তা নির্ধারণ করতে হাতের জয়েন্টগুলির কনভেনশনগুলির সাথে পরামর্শ করুন।

উদাহরণস্বরূপ, থাম্ব এবং তর্জনী দিয়ে একটি চিমটি সনাক্ত করতে, দুটি টিপ জয়েন্টের মধ্যে দূরত্ব ব্যবহার করুন:

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)

হাতের অঙ্গভঙ্গির জন্য কাস্টম সনাক্তকরণ বিকাশ করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • ব্যবহারকারীদের যেকোনো প্রদত্ত অঙ্গভঙ্গির ভিন্ন ব্যাখ্যা থাকতে পারে। উদাহরণস্বরূপ, কেউ কেউ আঙ্গুলগুলিকে স্প্লে করার জন্য একটি "স্টপ" ইঙ্গিত বিবেচনা করতে পারে, অন্যরা আঙ্গুলগুলিকে একত্রে বন্ধ করা আরও স্বজ্ঞাত বলে মনে করতে পারে।
  • কিছু অঙ্গভঙ্গি বজায় রাখা অস্বস্তিকর হতে পারে। স্বজ্ঞাত অঙ্গভঙ্গি ব্যবহার করুন যা ব্যবহারকারীর হাতে চাপ দেয় না।

ব্যবহারকারীর সেকেন্ডারি হাত নির্ধারণ করুন

অ্যান্ড্রয়েড সিস্টেম ব্যবহারকারীর প্রাথমিক হাতে সিস্টেম নেভিগেশন রাখে, যেমন ব্যবহারকারীর দ্বারা সিস্টেম পছন্দগুলিতে নির্দিষ্ট করা হয়েছে৷ সিস্টেম নেভিগেশন অঙ্গভঙ্গির সাথে দ্বন্দ্ব এড়াতে আপনার কাস্টম অঙ্গভঙ্গির জন্য সেকেন্ডারি হাত ব্যবহার করুন:

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)

,

জেটপ্যাক এক্সআর-এর জন্য ARCore ব্যবহারকারীর শনাক্ত করা হাত সম্পর্কে তথ্য প্রদান করতে পারে এবং হাত এবং তাদের সংযুক্ত জয়েন্টগুলির জন্য পোজ তথ্য দেয়। এই হ্যান্ড ডেটা ব্যবহারকারীর হাতে সত্তা এবং মডেল সংযুক্ত করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, একটি টুল মেনু:

একটি অধিবেশন প্রাপ্ত

একটি Android XR Session মাধ্যমে হাতের তথ্য অ্যাক্সেস করুন। একটি Session পাওয়ার জন্য একটি সেশনের জীবনচক্র বুঝতে দেখুন।

সেশন কনফিগার করুন

এক্সআর সেশনে ডিফল্টরূপে হ্যান্ড ট্র্যাকিং সক্ষম হয় না। হ্যান্ড ডেটা পেতে, সেশনটি কনফিগার করুন:

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

হাতের ডেটা পুনরুদ্ধার করুন

হাতের ডেটা বাম এবং ডান হাতের জন্য আলাদাভাবে উপলব্ধ। প্রতিটি জয়েন্টের জন্য পোজ পজিশন অ্যাক্সেস করতে প্রতিটি হাতের 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)
}

হাতের নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • isActive : হাত ট্র্যাক করা হচ্ছে কিনা।
  • handJoints : পোজ করার জন্য হাতের জয়েন্টগুলির একটি মানচিত্র। হাতের জয়েন্টের ভঙ্গি OpenXR মান দ্বারা নির্দিষ্ট করা হয়।

আপনার অ্যাপে হাতের ডেটা ব্যবহার করুন

ব্যবহারকারীর হাতের জয়েন্টগুলির অবস্থানগুলি ব্যবহারকারীর হাতে 3D বস্তুগুলিকে নোঙ্গর করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, বাম হাতের তালুতে একটি মডেল সংযুক্ত করতে:

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

অথবা আপনার ডান হাতের তর্জনীর ডগায় একটি মডেল সংযুক্ত করতে:

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

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করুন

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করতে হাতের জয়েন্টগুলির ভঙ্গি ব্যবহার করুন। প্রদত্ত ভঙ্গি হিসাবে নিবন্ধন করার জন্য জয়েন্টগুলি কোন সীমার ভঙ্গিতে থাকা উচিত তা নির্ধারণ করতে হাতের জয়েন্টগুলির কনভেনশনগুলির সাথে পরামর্শ করুন।

উদাহরণস্বরূপ, থাম্ব এবং তর্জনী দিয়ে একটি চিমটি সনাক্ত করতে, দুটি টিপ জয়েন্টের মধ্যে দূরত্ব ব্যবহার করুন:

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)

হাতের অঙ্গভঙ্গির জন্য কাস্টম সনাক্তকরণ বিকাশ করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • ব্যবহারকারীদের যেকোনো প্রদত্ত অঙ্গভঙ্গির ভিন্ন ব্যাখ্যা থাকতে পারে। উদাহরণস্বরূপ, কেউ কেউ আঙ্গুলগুলিকে স্প্লে করার জন্য একটি "স্টপ" ইঙ্গিত বিবেচনা করতে পারে, অন্যরা আঙ্গুলগুলিকে একত্রে বন্ধ করা আরও স্বজ্ঞাত বলে মনে করতে পারে।
  • কিছু অঙ্গভঙ্গি বজায় রাখা অস্বস্তিকর হতে পারে। স্বজ্ঞাত অঙ্গভঙ্গি ব্যবহার করুন যা ব্যবহারকারীর হাতে চাপ দেয় না।

ব্যবহারকারীর সেকেন্ডারি হাত নির্ধারণ করুন

অ্যান্ড্রয়েড সিস্টেম ব্যবহারকারীর প্রাথমিক হাতে সিস্টেম নেভিগেশন রাখে, যেমন ব্যবহারকারীর দ্বারা সিস্টেম পছন্দগুলিতে নির্দিষ্ট করা হয়েছে৷ সিস্টেম নেভিগেশন অঙ্গভঙ্গির সাথে দ্বন্দ্ব এড়াতে আপনার কাস্টম অঙ্গভঙ্গির জন্য সেকেন্ডারি হাত ব্যবহার করুন:

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)

,

জেটপ্যাক এক্সআর-এর জন্য ARCore ব্যবহারকারীর শনাক্ত করা হাত সম্পর্কে তথ্য প্রদান করতে পারে এবং হাত এবং তাদের সংযুক্ত জয়েন্টগুলির জন্য পোজ তথ্য দেয়। এই হ্যান্ড ডেটা ব্যবহারকারীর হাতে সত্তা এবং মডেল সংযুক্ত করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, একটি টুল মেনু:

একটি অধিবেশন প্রাপ্ত

একটি Android XR Session মাধ্যমে হাতের তথ্য অ্যাক্সেস করুন। একটি Session পাওয়ার জন্য একটি সেশনের জীবনচক্র বুঝতে দেখুন।

সেশন কনফিগার করুন

এক্সআর সেশনে ডিফল্টরূপে হ্যান্ড ট্র্যাকিং সক্ষম হয় না। হ্যান্ড ডেটা পেতে, সেশনটি কনফিগার করুন:

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

হাতের ডেটা পুনরুদ্ধার করুন

হাতের ডেটা বাম এবং ডান হাতের জন্য আলাদাভাবে উপলব্ধ। প্রতিটি জয়েন্টের জন্য পোজ পজিশন অ্যাক্সেস করতে প্রতিটি হাতের 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)
}

হাতের নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • isActive : হাত ট্র্যাক করা হচ্ছে কিনা।
  • handJoints : পোজ করার জন্য হাতের জয়েন্টগুলির একটি মানচিত্র। হাতের জয়েন্টের ভঙ্গি OpenXR মান দ্বারা নির্দিষ্ট করা হয়।

আপনার অ্যাপে হাতের ডেটা ব্যবহার করুন

ব্যবহারকারীর হাতের জয়েন্টগুলির অবস্থানগুলি ব্যবহারকারীর হাতে 3D বস্তুগুলিকে নোঙ্গর করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, বাম হাতের তালুতে একটি মডেল সংযুক্ত করতে:

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

অথবা আপনার ডান হাতের তর্জনীর ডগায় একটি মডেল সংযুক্ত করতে:

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

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করুন

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করতে হাতের জয়েন্টগুলির ভঙ্গি ব্যবহার করুন। প্রদত্ত ভঙ্গি হিসাবে নিবন্ধন করার জন্য জয়েন্টগুলি কোন সীমার ভঙ্গিতে থাকা উচিত তা নির্ধারণ করতে হাতের জয়েন্টগুলির কনভেনশনগুলির সাথে পরামর্শ করুন।

উদাহরণস্বরূপ, থাম্ব এবং তর্জনী দিয়ে একটি চিমটি সনাক্ত করতে, দুটি টিপ জয়েন্টের মধ্যে দূরত্ব ব্যবহার করুন:

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)

হাতের অঙ্গভঙ্গির জন্য কাস্টম সনাক্তকরণ বিকাশ করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • ব্যবহারকারীদের যেকোনো প্রদত্ত অঙ্গভঙ্গির ভিন্ন ব্যাখ্যা থাকতে পারে। উদাহরণস্বরূপ, কেউ কেউ আঙ্গুলগুলিকে স্প্লে করার জন্য একটি "স্টপ" ইঙ্গিত বিবেচনা করতে পারে, অন্যরা আঙ্গুলগুলিকে একত্রে বন্ধ করা আরও স্বজ্ঞাত বলে মনে করতে পারে।
  • কিছু অঙ্গভঙ্গি বজায় রাখা অস্বস্তিকর হতে পারে। স্বজ্ঞাত অঙ্গভঙ্গি ব্যবহার করুন যা ব্যবহারকারীর হাতে চাপ দেয় না।

ব্যবহারকারীর সেকেন্ডারি হাত নির্ধারণ করুন

অ্যান্ড্রয়েড সিস্টেম ব্যবহারকারীর প্রাথমিক হাতে সিস্টেম নেভিগেশন রাখে, যেমন ব্যবহারকারীর দ্বারা সিস্টেম পছন্দগুলিতে নির্দিষ্ট করা হয়েছে৷ সিস্টেম নেভিগেশন অঙ্গভঙ্গির সাথে দ্বন্দ্ব এড়াতে আপনার কাস্টম অঙ্গভঙ্গির জন্য সেকেন্ডারি হাত ব্যবহার করুন:

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)

,

জেটপ্যাক এক্সআর-এর জন্য ARCore ব্যবহারকারীর শনাক্ত করা হাত সম্পর্কে তথ্য প্রদান করতে পারে এবং হাত এবং তাদের সংযুক্ত জয়েন্টগুলির জন্য পোজ তথ্য দেয়। এই হ্যান্ড ডেটা ব্যবহারকারীর হাতে সত্তা এবং মডেল সংযুক্ত করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, একটি টুল মেনু:

একটি অধিবেশন প্রাপ্ত

একটি Android XR Session মাধ্যমে হাতের তথ্য অ্যাক্সেস করুন। একটি Session পাওয়ার জন্য একটি সেশনের জীবনচক্র বুঝতে দেখুন।

সেশন কনফিগার করুন

এক্সআর সেশনে ডিফল্টরূপে হ্যান্ড ট্র্যাকিং সক্ষম হয় না। হ্যান্ড ডেটা পেতে, সেশনটি কনফিগার করুন:

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

হাতের ডেটা পুনরুদ্ধার করুন

হাতের ডেটা বাম এবং ডান হাতের জন্য আলাদাভাবে উপলব্ধ। প্রতিটি জয়েন্টের জন্য পোজ পজিশন অ্যাক্সেস করতে প্রতিটি হাতের 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)
}

হাতের নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • isActive : হাত ট্র্যাক করা হচ্ছে কিনা।
  • handJoints : পোজ করার জন্য হাতের জয়েন্টগুলির একটি মানচিত্র। হাতের জয়েন্টের ভঙ্গি OpenXR মান দ্বারা নির্দিষ্ট করা হয়।

আপনার অ্যাপে হাতের ডেটা ব্যবহার করুন

ব্যবহারকারীর হাতের জয়েন্টগুলির অবস্থানগুলি ব্যবহারকারীর হাতে 3D বস্তুগুলিকে নোঙ্গর করতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ, বাম হাতের তালুতে একটি মডেল সংযুক্ত করতে:

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

অথবা আপনার ডান হাতের তর্জনীর ডগায় একটি মডেল সংযুক্ত করতে:

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

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করুন

প্রাথমিক হাতের অঙ্গভঙ্গি সনাক্ত করতে হাতের জয়েন্টগুলির ভঙ্গি ব্যবহার করুন। প্রদত্ত ভঙ্গি হিসাবে নিবন্ধন করার জন্য জয়েন্টগুলি কোন সীমার ভঙ্গিতে থাকা উচিত তা নির্ধারণ করতে হাতের জয়েন্টগুলির কনভেনশনগুলির সাথে পরামর্শ করুন।

উদাহরণস্বরূপ, থাম্ব এবং তর্জনী দিয়ে একটি চিমটি সনাক্ত করতে, দুটি টিপ জয়েন্টের মধ্যে দূরত্ব ব্যবহার করুন:

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)

হাতের অঙ্গভঙ্গির জন্য কাস্টম সনাক্তকরণ বিকাশ করার সময় নিম্নলিখিত বিষয়গুলি মনে রাখবেন:

  • ব্যবহারকারীদের যেকোনো প্রদত্ত অঙ্গভঙ্গির ভিন্ন ব্যাখ্যা থাকতে পারে। উদাহরণস্বরূপ, কেউ কেউ আঙ্গুলগুলিকে স্প্লে করার জন্য একটি "স্টপ" ইঙ্গিত বিবেচনা করতে পারে, অন্যরা আঙ্গুলগুলিকে একত্রে বন্ধ করা আরও স্বজ্ঞাত বলে মনে করতে পারে।
  • কিছু অঙ্গভঙ্গি বজায় রাখা অস্বস্তিকর হতে পারে। স্বজ্ঞাত অঙ্গভঙ্গি ব্যবহার করুন যা ব্যবহারকারীর হাতে চাপ দেয় না।

ব্যবহারকারীর সেকেন্ডারি হাত নির্ধারণ করুন

অ্যান্ড্রয়েড সিস্টেম ব্যবহারকারীর প্রাথমিক হাতে সিস্টেম নেভিগেশন রাখে, যেমন ব্যবহারকারীর দ্বারা সিস্টেম পছন্দগুলিতে নির্দিষ্ট করা হয়েছে৷ সিস্টেম নেভিগেশন অঙ্গভঙ্গির সাথে দ্বন্দ্ব এড়াতে আপনার কাস্টম অঙ্গভঙ্গির জন্য সেকেন্ডারি হাত ব্যবহার করুন:

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)