Android XR

تصميم المحتوى المكاني على Android XR باستخدام Unity

سماعات

  • ليفانا تشن

    مهندس برمجيات

  • جينيفر ستانتون

    كبير مهندسي البرامج

لمحة

لمحة عن المحاضرة

اكتشِف كيفية تثبيت تجارب ثلاثية الأبعاد وحفظها في العالم الواقعي باستخدام Unity وAndroid XR. تتناول هذه الجلسة إطار عمل Spatial Entities وCloud Anchors وGeospatial API، وتوضّح كيفية إنشاء تطبيقات ذكية تتذكّر المواقع الجغرافية وتزامن البيانات المكانية لعدة مستخدمين على مستوى الجلسات.

سنستكشف البنية الأساسية للكيانات المكانية، ونتعرّف على كيفية ربط الأصول الرقمية بالأجسام المادية والأسطح والمواقع الجغرافية. ستتعرّف على سير عمل Unity العملي لتحديد المساحات، والحفاظ على المحتوى في جميع الجلسات، وإنشاء تجارب واقع معزّز/واقع ممتد مشتركة تتعرّف على الموقع الجغرافي.

ملخّص

  • توفّر AR Foundation واجهة برمجة تطبيقات موحّدة للنصوص البرمجية على مستوى منصات الواقع الممتد باستخدام إضافات OpenXR. تتيح لك هذه الواجهة تمثيل ميزات العالم الحقيقي والاستعلام عنها، مثل الأسطح المستوية والشبكات.
  • تساعد نقاط الارتساء الثابتة في تثبيت المحتوى الرقمي على مستوى الجلسات وعمليات إعادة تشغيل الجهاز. يمكنك الاحتفاظ بها باستخدام TrySaveAnchorAsync وإعادة تحميلها باستخدام معرّفات GUID المتسلسلة.
  • يحلّ إطار عمل Spatial Entities محلّ الإضافات القابلة للتتبُّع لتوفير الدعم من عدّة منصات وأداء أفضل لتتبُّع العناصر، مثل المربّعات المحيطة والعلامات.
  • يجب إيقاف مكوّنات المدير إلى أن يتم منح أذونات Android XR. يؤدي ذلك إلى تجنُّب حالات تعذُّر بدء تشغيل النظام الفرعي بسبب الوصول المقيّد إلى بيانات البيئة الحسّاسة.
  • تستخدم واجهة Geospatial API خدمات Google Cloud ARCore ونظام تحديد المواقع المرئي (VPS) لتحديد موضع المحتوى في المواقع الجغرافية الخارجية في العالم الحقيقي.

الموارد

Gemini Notebook

المواضيع

  • android-xr
  • اتّحاد
  • ar-foundation
  • openxr
  • spatial-entities
  • إعلانات ثابتة
  • geospatial-api

النص

تنزيل النص

مقدمة ونظرة عامة حول AR Foundation

  • حسنًا.

  • مرحبًا بالجميع.

  • هذا هو الدرس "تصميم المحتوى المكاني على Android XR باستخدام Unity".

  • اسمي جينيفر ستانتون.

  • أعمل في Unity كمهندس برمجيات أول.

  • أعمل في فريق ميزات الواقع الممتد، وتحديدًا على AR Foundation والحزم ذات الصلة التي تتيح استخدام الواقع المعزّز والمختلط في Unity.

  • اسمي "ليفانا تشن"، وأنا من فريق محرّكات ألعاب الواقع الممتد في Google.

  • ركّزت فِرقنا على تقديم المكوّنات الإضافية والحِزم التي توفّر وظائف محسّنة للواقع الممتد وعمليات دمج سلسة لمحرّكات الألعاب.

  • من أكبر التحديات التي يواجهها المطوّرون هي أنّ دعم منصات XR متعددة باستخدام قاعدة الرموز البرمجية نفسها يتطلّب الكثير من العمل.

  • ‫AR Foundation هي طبقة واجهة برمجة تطبيقات عالية المستوى للواقع الممتد من Unity.

  • يمكنك استهداف منصات XR متعددة بدون إعادة كتابة الرموز البرمجية بشكل كبير أو إدارة قواعد رموز برمجية متعددة، كما تمنحك واجهة برمجة تطبيقات واحدة لميزات الواقع المعزّز على أي منصة.

  • يتيح لك ذلك التركيز على إنشاء تطبيقك أو لعبتك أو تجربتك، وتتولى Unity تفاصيل المنصة نيابةً عنك.

  • وتحقّق حزمة AR Foundation ذلك من خلال إضافات OpenXR.

  • وهي مجموعة من واجهات برمجة التطبيقات المفتوحة والمتّبعة في المجال والتي حدّدتها مجموعة Khronos.

  • أنشأت OpenXR أيضًا "كيانات مكانية".

  • وهو إطار عمل للمحتوى الرقمي لتمثيل العالم المادي والتفاعل معه.

  • توفّر "الكيانات المكانية" نموذجًا موحّدًا لتمثيل العناصر الواقعية كعناصر رقمية.

  • يسرّني أن أشارككم بعضًا من أحدث المعلومات حول AR Foundation لتبدأوا رحلتكم في إنشاء تجارب للواقع الممتد.

  • بعد ذلك، سأستعرض إمكانات AR Foundation لكي يتمكّن المحتوى الرقمي من التفاعل مع العالم الحقيقي.

  • بعد ذلك، سأشرح كيفية إعداد المشروع، بما في ذلك الحِزم والتبعيات الأخرى، لتتمكّن من تطبيق ذلك في مشاريعك.

  • بعد ذلك، سأختتم حديثي باستعراض بعض الميزات الفريدة في Android XR.

الميزات الرئيسية في AR Foundation

  • إذًا، من بين الطرق التي تمثّل بها AR Foundation العالم الحقيقي رقميًا هي المستويات.

  • وهي أسطح مستوية في البيئة المادية، مثل الأرضيات والجدران والأسقف وحتى الطاولات والأرائك.

  • الشبكات هي هياكل ثلاثية الأبعاد تمثّل الشكل الهندسي للعالم المادي.

  • ولدينا أيضًا طرق للتفاعل مع العالم الحقيقي، مثل تقنية "راي كاست" (Ray Cast).

  • تحدّد هذه النقاط مكان تقاطع الشعاع مع المحتوى الرقمي.

  • يمكنك اعتبارها مؤشر ليزر، وستحصل على معلومات حول المكان الذي يضيء فيه مؤشر الليزر هذا.

  • لدينا أيضًا نقاط ارتساء، والتي تساعد في تثبيت نقطة في الفضاء ونقلها.

  • سأتعمّق في الحديث عن نقاط الارتكاز لاحقًا في هذا العرض التقديمي.

  • لذا، تُعتبر هذه الميزات الأربع من ميزات AR Foundation.

  • هناك أيضًا بعض الميزات الأخرى التي لم يتم ذكرها في هذه الشريحة.

  • تُعتبر المستويات والمثبّتات تحديدًا من العناصر القابلة للتتبّع لأنّها توسّع فئة ARTrackable، ويتتبّع مدراؤها التحديثات من وقت التشغيل.

  • لنتحدّث الآن عن الطائرات.

  • بالنسبة إلى الأسطح، لدينا مكوّن ARPlane الذي يوفّر إمكانية التعرّف على الأسطح المستوية في الوقت الفعلي.

  • وتتضمّن تصنيفات دلالية يمكنك الاستعلام عنها لمعرفة ما إذا كان السطح أرضية أو طاولة أو جدارًا أو غير ذلك.

  • تتضمّن المستويات أيضًا حدودًا ديناميكية، لذا عندما يتحرّك المستخدم في العالم الحقيقي ويتمكّن من رؤية المزيد من الأسطح، ستتوسّع حدود المستوى وتندمج وتتحسّن ديناميكيًا في الوقت الفعلي.

  • يمكننا أيضًا إرفاق مصادم شبكي بالطائرة للتعامل مع الفيزياء.

  • يمكنك هنا الاطّلاع على مثال على رصد السطح المستوي.

  • هذا هو مشهد شعاعي من عيّنات AR Foundation يتم تشغيله على جهاز Android XR.

  • ترصد هذه الميزة المضلّعات الديناميكية الثنائية الأبعاد في الوقت الفعلي.

  • يمكنك إنشاء تطبيق يتضمّن هذه الوظيفة باتّباع دليل إعداد المشروع أو باستخدام أحد النماذج أو القوالب.

  • بعد ذلك، لدينا الشبكات.

  • "الشبكات" هي ميزة واقع معزّز توفّر شبكات ثلاثية الأبعاد للبيئة.

  • يمكننا إرفاق مصادم شبكي بهذه الشبكات التي تم إنشاؤها، ما يسمح للمحتوى الرقمي بالتفاعل مع العناصر في العالم الحقيقي.

  • تتيح الشبكات إخفاء العناصر بشكل مقنع.

  • وبالتالي، يمكن أن يظهر عنصر افتراضي خلف عنصر مادي.

  • إذا كان بإمكان العنصر الرقمي التحرّك في المساحة، يمكنك استخدام الشكل الهندسي نفسه للعثور على مسار يتجنّب العناصر في العالم الحقيقي.

  • بعد ذلك، لدينا ميزة "إسقاط الأشعة".

  • تُسقط ميزة "تتبُّع الشعاع" (Ray casting) أشعة افتراضية في المشهد الثلاثي الأبعاد للبحث عن التقاطعات بدون الحاجة إلى القلق بشأن العمليات الحسابية المعقدة.

  • يمكن أن يتقاطع الشعاع المُسقَط مع عناصر ثلاثية الأبعاد متعددة في بيئتك.

  • يمكنك ضبط شعاع الأشعة ليصيب أنواعًا معيّنة فقط من المحتوى الرقمي.

  • على سبيل المثال، يمكنك ضبطه لعدم الاصطدام بالمستويات والتقاطع مع الشبكات فقط.

إعداد الحزم والتبعيات

  • لنلقِ نظرة الآن على الحزم ذات الصلة.

  • تعمل هذه الحزم معًا للتواصل مع بعضها وإنشاء تجربة واقع ممتد كاملة.

  • كما ذكرنا، تتعامل AR Foundation مع ميزات مثل المستويات والمثبّتات.

  • يتعامل المكوّن الإضافي OpenXR مع واجهات برمجة التطبيقات الأصلية على منصات XR المختلفة، لذا ننصحك باستخدام هذه الحزمة إذا كان جهازك يستخدم OpenXR.

  • يمكن إقران المكوّن الإضافي OpenXR اختياريًا بحزمة OpenXR Spatial Entities للوصول إلى إضافات Spatial Entities تحديدًا، وسنتناول ذلك بمزيد من التفصيل لاحقًا.

  • إذا كنت تعرف أنّك ستستهدف أجهزة Android XR تحديدًا، مثل سماعات الرأس والنظارات السلكية بنظام الواقع الممتد، فستحتاج إلى حزمة Unity OpenXR Android XR.

  • وبما أنّ كل ذلك يتّبع نمط المكوّن الإضافي، من المفترض أن يكون التأثير في الرمز البرمجي ضئيلاً.

  • لا تتوفّر بعض الميزات في بعض حزم AR Foundation.

  • على سبيل المثال، إذا نظرت إلى هذا الرسم البياني، ستجد أنّ ميزة "الشبكة" غير متاحة حاليًا في حزمة Unity OpenXR Spatial Entities.

  • تتيح لك ميزة "إدارة المكوّنات الإضافية لتقنيات الواقع الممتد" (XR Plug-in Management) إدارة ميزات OpenXR التي يتم اختيارها في مشروعك.

  • لذا، إذا كنت تستخدم محرِّر Unity، عليك الانتقال إلى "تعديل" (Edit)، ثم "إعدادات المشروع" (Project Settings)، ثم "إدارة المكوّنات الإضافية لتقنيات الواقع الممتد" (XR Plug-in Management) في الشريط الجانبي الأيمن.

  • وهنا يمكنك العثور على ميزات OpenXR ومجموعات الميزات، بحيث يمكنك اختيار وإلغاء اختيار الميزات ومجموعات الميزات التي تريد تضمينها في الإصدار.

  • على سبيل المثال، في لقطة الشاشة هذه، نرى جميع المكوّنات التي تأتي مع حزمة Android XR OpenXR.

  • ويمكنك بعد ذلك مزج هذه الكيانات ومطابقتها مع الكيانات المكانية، على سبيل المثال، إذا أردت ذلك.

  • إليكم نافذة Package Manager (مدير الحِزم).

  • لقد سلّطت الضوء على بعض الحزم التي قد تظهر لك في إعداد مشروع XR عادي.

  • كما ترون، لدينا AR Foundation التي سبق ذكرها.

  • لدينا أيضًا المكوّن الإضافي OpenXR.

  • لدينا حزمة Android XR.

  • لقد سلّطت الضوء أيضًا على بعض المنصات الأخرى لأنّه يمكنك بالتأكيد إنشاء مشروع يتوافق مع منصات متعددة.

  • ولدينا أيضًا في أسفل يسار الشاشة بعض الحزم الأخرى أيضًا.

  • وComposition Layers التي تعمل مع أجهزة OpenXR، وCore Utils المفيدة جدًا لأي شيء يتعلّق بالواقع الممتد، وXR Hands وXR Interaction Toolkit للحصول على الإدخالات، وهو أمر ضروري للغاية.

  • لذا، لدينا بعد ذلك التحقق من صحة المشروع.

  • هذا أيضًا جزء من "إدارة المكوّنات الإضافية لتقنيات الواقع الممتد" (XR Plug-in Management).

  • يمكن أن ترصد عملية التحقّق من المشروع الميزات المكرّرة، بالإضافة إلى المشاكل الأخرى في مشروعك التي تحتاج إلى إصلاحها لتشغيله.

  • ولكن في لقطة الشاشة هذه، قمت بتمييز الميزات المكررة.

  • ما يعنيه هذا في الأساس هو ميزتان من الميزات نفسها، مثل أعتقد أن لدينا نقاط ارتساء، وربما مستويات وأشعة هنا.

  • اختار المستخدم تضمين نُسخ مكرّرة من هذه الميزات من حِزم متعددة، ويطلب منه فقط اختيار إحداها.

نقاط الارتكاز المحلية واستمرار ظهورها

  • وهذا يقودنا إلى نقاط الارتكاز المحلية والثبات.

  • تضمن نقاط الارتكاز بقاء المحتوى الرقمي في المواقع المطلوبة في البيئة بغض النظر عن التغييرات في حالة تتبُّع جلسة الواقع المعزّز.

  • تعمل منصات الواقع المعزّز على تعديل وضعيات نقاط الارتكاز تلقائيًا بمرور الوقت لضمان بقائها في موضع ثابت، وتُعدّ نقاط الارتكاز أفضل طريقة لضمان بقاء المحتوى في مكانه إذا ابتعدت عن نقطة الارتكاز ثم عدت إليها.

  • وماذا يحدث عندما يغلق المستخدم تطبيقه ويعيد تشغيله لاحقًا ويعود إليه في جلسة منفصلة؟

  • تتيح لك نقاط الارتساء الثابتة حفظ نقاط الارتساء في جلسة واقع معزّز ثم تحميلها في الجلسات اللاحقة.

  • وتظل هذه البيانات محفوظة حتى بعد انتهاء دورة حياة التطبيق وإعادة تشغيل الجهاز.

  • تظهر هنا عيّنة نقاط الارتكاز الدائمة في مشروع AR Foundation Samples.

  • يحتوي المشهد النموذجي على قائمة تتضمّن جميع الوظائف المتوافقة مع تلك المنصة، مثل حفظ نقاط الارتكاز وتحميلها.

  • وهذا يقودنا إلى دورة حياة نقاط الارتكاز الثابتة.

  • أولاً، عليك إنشاء نقطة ارتساء على الجهاز، بحيث لا يتم حفظها في أي مكان بعد، ولا يتم حفظها في مساحة تخزين دائمة، بل تكون مجرد نقطة ارتساء على الجهاز.

  • وبعد ذلك، يمكنك الاحتفاظ بها في مساحة التخزين.

  • بعد ذلك، يمكنك إعادة تشغيل التطبيق، ثم تحميله من مساحة التخزين.

  • تتيح بعض المنصات، بما في ذلك Android XR، محو نقاط الارتكاز أو إلغاء تثبيتها.

  • يتيح موفّر "الكيانات المكانية" تحميل جميع نقاط الارتكاز المحفوظة تلقائيًا كي لا تضطر إلى طلب كل نقطة ارتكاز يدويًا باستخدام رقم تعريفها.

  • في إعدادات XR Plug-in Management، يمكنك تحديد خيار "تحميل نقاط الارتكاز المحفوظة تلقائيًا" (Automatically Load Saved Anchors) في ميزة "نقاط الارتكاز" (Anchors) ضمن "الكيانات المكانية" (Spatial Entities).

  • ولا يتطلّب حفظ نقطة ارتساء سوى بضعة أسطر من الرموز البرمجية.

  • أولاً، نبدأ في محرّر Unity ونتأكّد من أنّ المشهد جاهز من خلال إضافة مكوّن AR Anchor Manager إلى عنصر لعبة XR Origin.

  • يُبقي المدير المشهد محدَّثًا باستخدام نقاط الارتكاز التي يتم تتبُّعها من وقت التشغيل.

  • هذا يقودنا إلى الرمز.

  • لإضافة نقطة ارتساء، يمكنك ببساطة استدعاء TryAddAnchorAsync وتمرير وضعية المكان الذي تريد وضع نقطة الارتساء فيه.

    async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
        var result = await manager.TryAddAnchorAsync(pose);
        if (result.status.IsError()) {
            // handle error
            return;
        }
        var anchor = result.value;
    }
  • بعد ذلك، لدينا إزالة نقاط الارتساء.

    void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
        var result = manager.TryRemoveAnchor(anchor.trackableId);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    }
    
    void DestroyAnchorComponent(ARAnchor anchor) {
        Destroy(anchor);
    }
  • وبالمثل، فهو مجرد سطر واحد من التعليمات البرمجية.

  • عند استدعاء TryRemoveAnchor، يتم تمرير المعرّف القابل للتتبّع للمرساة.

  • عند إنشاء الارتساء، تم منحه بالفعل معرّفًا قابلاً للتتبع.

  • ولدينا أيضًا "TrySaveAnchorAsync".

    async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
        var result = await manager.TrySaveAnchorAsync(anchor);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    
        // Save this value, then return it as an input parameter
        SerializableGuid guid = result.value;
    }
  • يتم تمرير نقطة ارتساء في الواقع المعزّز كإدخال.

  • تعرض هذه الدالة SerializableGuid يحدّد نقطة الارتكاز في مساحة التخزين الدائمة.

  • يمكنك لاحقًا استخدام المعرّف الفريد العالمي (GUID) عند تحميل علامة الارتساء.

  • وهذا يقودنا إلى تحميل نقاط الارتكاز.

    async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
        var result = await manager.TryLoadAnchorAsync(guid);
        if (result.status.IsError()) {
            // handle error
            return;
        }
    
        ARAnchor anchor = result.value;
    }
  • الدالة التي يجب استدعاؤها هنا هي TryLoadAnchorAsync، ويجب تمرير المعرّف الفريد العالمي (GUID) الذي تم تسلسله من قبل.

  • وستعرض نقطة ارتساء للواقع المعزّز كنتيجة.

  • هذا كل ما في الأمر.

  • تتيح لك هذه الدوال إدارة كل من نقاط الارتكاز المحلية والثابتة بسهولة.

  • لذلك، يُعد تتبع الارتساء مهمة مكلفة إلى حد ما في معظم منصات الواقع المعزز.

  • عند العمل مع نقاط الارتكاز، ننصحك باتّباع أفضل الممارسات التالية: تجنَّب إنشاء نقاط ارتكاز متعددة قريبة جدًا من بعضها، وفكِّر في ما إذا كان بإمكانك استخدام نقطة ارتكاز قريبة بدلاً من إنشاء نقطة أخرى، وأزِل نقاط الارتكاز عندما لا تعود بحاجة إليها، وأخيرًا، إذا فعّلت ميزة أخرى من ميزات الواقع المعزّز للمساعدة في حساب الوضع المطلوب لنقطة ارتكاز، فكِّر في ما إذا كان بإمكانك إيقاف هذه الميزة بعد إنشاء نقطة الارتكاز بنجاح.

  • والآن، سأترك الكلمة لـ "ليفانا".

حزمة تطوير البرامج (SDK) لمنصة Android XR في Unity

  • شكرًا، نهال.

  • بعد ذلك، سأشرح لكم مساهمة Google في رحلة Android XR في Unity.

  • لذلك، بالإضافة إلى مكوّنات Unity OpenXR الإضافية التي قدّمتها "جينيفر" حتى الآن، توفّر Google حزمة تطوير البرامج (SDK) لنظام Android XR في Unity مع إمكانات إضافية متاحة على نظام Android XR الأساسي.

  • تحتوي حزمة SDK هذه على الكثير من الميزات والحزم، وفي هذه الجلسة، سنركّز على حزمة Android XR Extension for Unity.

  • لذلك، على غرار OpenXR Android XR وOpenXR Spatial Entities، فإنّ حزمة Android XR Extension for Unity هي في الواقع موفّر OpenXR.

  • وتبدو بنية هذه الحزمة على النحو التالي، ويمكنها العمل بشكل متوازٍ أو مستقل.

  • لذا، مثل جميع مقدّمي خدمات OpenXR الآخرين، تم إنشاء حزمة Google مباشرةً على واجهة OpenXR العادية.

  • لذلك، نعرض هنا مجموعة من الميزات كمقارنة بين جميع مقدّمي الخدمات الآخرين.

  • لذلك، يمكنك مساعدتك في اتخاذ قرار بشأن متى ولماذا تختار أحدهما على الآخر.

  • لذا، قد يكون لديك سؤال حول العلامة القابلة للتتبّع وعلامة الكيان المكاني المعروضة في هذا الجدول.

  • إليك ملاحظة جانبية: بالنسبة إلى المطوّرين الذين سبق لهم إنشاء تطبيقات وتجارب على Android XR، قدّمنا هذه الميزات من خلال الإضافات القابلة للتتبّع والتي تعمل فقط على Android XR.

  • بعد ذلك، كما ذكرت "جينيفر"، عملنا كمجموعة مفتوحة في OpenXR، ثم أصدرنا إضافة Spatial Entities Extension على الجانب الأيمن وقدّمنا تجربة متّسقة ومتوافقة مع عدّة منصات.

  • ونعمل حاليًا على إيقاف الإضافة القابلة للتتبّع نهائيًا لصالح إطار عمل Spatial Entities.

  • ليس فقط لأنّ الأخير أكثر كفاءة، بل أيضًا لأنّه يتيح العمل من عدّة منصات.

الإنشاء باستخدام الكيانات المكانية

  • بعد ذلك، لنلقِ نظرة عن قرب على الكيانات المكانية.

  • بالإضافة إلى ما ذكرته "جينيفر" عن المستويات وإسقاط الأشعة والمثبّتات، يمكنكم أيضًا العثور على هذه الميزة التي يوفّرها مقدّمو الكيانات المكانية، مثل العلامات التي يمكنها رصد الرموز الشريطية الثنائية الأبعاد العادية وفك ترميزها وتتبُّع موضعها في المساحة الثلاثية الأبعاد، والصورة التي ستتعرّف على الرسومات الثنائية الأبعاد المعروفة وتتبُّعها في المساحة الثلاثية الأبعاد.

  • بعد ذلك، يحدّد المربّع المحيط العنصر المادي، مثل لوحة المفاتيح أو الكمبيوتر المحمول أو الماوس، ويتتبّع المربّع المحيط به في وضعية ثلاثية الأبعاد.

  • وفي المثال التالي، سنضبط ميزة المربّع المحيط التي توفّرها حزمة إضافات Google.

  • لذا، فإنّ طريقة العرض هذه هي نفسها تقريبًا لجميع ميزات OpenXR.

  • لذا، عليك أولاً التبديل إلى نظام Android XR الأساسي، ثم تفعيل موفّر OpenXR واختيار ميزة OpenXR التي تريد استخدامها في عملية الإنشاء، على سبيل المثال، تم عرض ميزة المربّع المحيط بالكيان المكاني هنا، ثم حلّ مشاكل التحقّق من المشروع.

  • سيساعدك ذلك في العثور على جميع التبعيات المطلوبة لميزة معيّنة ثم حلّ التعارضات الناتجة عن ميزات متعددة تساهم في النظام الفرعي نفسه.

  • في بعض الأحيان، تحتاج في الغالب إلى اختيار ميزة واحدة فقط إذا كنت تريد استخدام، على سبيل المثال، نقطة ارتساء أو مستوى أو مربع إحاطة هنا.

  • وأخيرًا، يمكنك إنشاء المشهد النموذجي أو مشهد الاختبار.

  • للوصول إلى العنصر القابل للتتبُّع في وقت التشغيل، يمكنك ببساطة إضافة مكوّن إدارة مربّع الإحاطة في الواقع المعزّز، وهو مكوّن مشابه لمكوّن إدارة نقاط الارتكاز في الواقع المعزّز، ثم استخدام واجهة AR Foundation للوصول إليه.

  • ويمكنك أيضًا استيراد نموذج الكيان المكاني الذي توفّره حزمة الإضافة كنموذج للبدء به.

  • إليك الفرق الرئيسي عند استخدام ميزة AR Foundation على Android XR.

  • للمساعدة في فهم البيئة المحيطة بالمستخدم، يحتاج تطبيقك عادةً إلى الوصول إلى البيانات الحسّاسة المتعلّقة بالبيئة.

  • ولحماية المستخدم، يقيّد نظام Android XR الوصول إلى البيانات التي تتطلب أذونات.

  • قد تكون على دراية بذلك، مثل طلب إذن Android العادي، مثل الوصول إلى الكاميرا أو الوصول إلى الموقع الجغرافي، وأشياء من هذا القبيل.

  • وأفضل ممارسة هنا هي إيقاف مكوّن المدير عند بدء التشغيل، إما من المحرِّر، كما هو موضّح على الجانب الأيسر، أو من النص البرمجي، مثل حدث Awake.

    void Awake() {
        planeManager = GetComponent<ARPlaneManager>();
        planeManager.enabled = false;
        boundingBoxManager = GetComponent<ARBoundingBoxManager>();
        boundingBoxManager.enabled = false;
        permissionUtil = GetComponent<AndroidXRPermissionUtil>();
    }
    
    void OnEnable() {
        StartCoroutine(WaitForPermissions());
    }
  • وبعد منح كل الأذونات المطلوبة، يمكنك تفعيل المدير من النص البرمجي، مثل ما يفعله مساعد WaitForPermissions هنا.

    IEnumerator WaitForPermissions() {
        planeManager.enabled = false;
        boundingBoxManager.enabled = false;
    
        yield return new WaitUntil(() =>
            permissionUtil.AllPermissionGranted());
    
        // Enable after granted permissions and
        // restart subsystems.
        planeManager.enabled = true;
        boundingBoxManager.enabled = true;
    
        // Save permission status.
        permissionGranted = true;
    }
  • وبذلك، يمكنك تجنُّب تعذُّر إعداد النظام الفرعي بسبب عدم كفاية الأذونات.

  • وهذه ميزة خاصة هنا.

  • كما شرحت "جينيفر" بشأن نقاط الارتكاز باستخدام AR Foundation، لتوسيع إمكانات نقاط الارتكاز على Android XR، توفّر حزمتنا أيضًا ميزة جديدة تُسمى نقاط الارتكاز القابلة للمشاركة.

  • تكرّر هذه الميزة ما تتيحه حاليًا ميزة الإرساء في AR Foundation، وتتضمّن أيضًا بعض الوظائف الإضافية، مثل نقاط الارتكاز الجغرافية المكانية.

  • وكما تتخيّل، فإنّ نقاط الارتكاز هي الجسر الحقيقي الذي يربط بين العالمَين الافتراضي والمادي.

  • وعلى الرغم من أنّ "جينيفر" شرحت لنا كيفية إنشاء هذه العناصر وحفظها وتحميلها، إلا أنّ كل ذلك حدث في مساحة محلية، مثل الشاشات الكبيرة الخاصة بالمستخدم.

  • ولكن ماذا عن بقية بلدان العالم؟

  • وكيف يمكننا مشاركتها مع بعضنا البعض؟

Geospatial API

  • وهنا يأتي دور Geospatial API.

  • تتيح لك هذه الواجهة إنشاء نقطة ارتساء جغرافية مكانية استنادًا إلى موقع جغرافي في العالم الحقيقي، مثل متجر الكتب المفضّل لديك أو مكان اجتماع في حديقة كبيرة.

  • لذلك، يمكن أن توفّر لك Geospatial API أداة تتبُّع دقيقة للموقع الجغرافي من خلال نظام تحديد المواقع الافتراضي (VPS)، وهو يشبه نظام تحديد المواقع العالمي (GPS)، ولكنّه يستخدم بيانات "التجوّل الافتراضي" في الأماكن الخارجية لتقديم نتائج تتبُّع أكثر دقة.

  • لذا، قد يكون بعضكم على دراية بهذا العرض إذا كانت لديكم خبرة سابقة في استخدام ميزة ARCore الجغرافية المكانية.

  • لذلك، للوصول إلى Geospatial API على Android XR، نحتاج أولاً إلى الاتصال بالخلفية المستضافة على Google Cloud Platform.

  • بما أنّ الخلفية الجغرافية المكانية تستند في الواقع إلى خدمة ARCore على Google Cloud، يمكنك اتّباع الخطوة نفسها بالضبط لضبط مشروعك على السحابة الإلكترونية من Google من خلال الوصول إلى ARCore API.

  • كل هذا سيتيح بعد ذلك استخدام ميزة Android XR Google Cloud التي توفّرها حزمة الإضافات.

  • بعد تفعيل Geospatial API والحصول على مفتاح واجهة برمجة التطبيقات من مشروع Google Cloud، يمكنك تفعيل هذه الميزة وضبط المصادقة من خلال قائمة إعدادات OpenXR المعروضة هنا، أو يمكنك ضبطها يدويًا من خلال واجهة برمجة التطبيقات الخاصة بالبرمجة النصية والتي تُسمى TrySetAuthenticationAsync.

    async Task TrySetAuthentication() {
        googleCloudFeature =
            OpenXRSettings.Instance
                .GetFeature<XRGoogleCloudFeature>();
        var result = await googleCloudFeature
            .TrySetAuthenticationAsync(
                strategy, credential);
        if (result.IsSuccess()) {
            // Ready to use for geospatial tracker.
        } else if (result.IsUnsupported())  {
            // Google Cloud feature is not supported
        } else if (result.IsKeylessError()) {
            // Confirm if keyless has been set up properly.
        } else {
            // Handling other common OpenXR errors.
        }
    }
  • تجدر الإشارة إلى أنّ منصة Android XR لا تتيح حاليًا سوى المصادقة باستخدام مفتاح واجهة برمجة التطبيقات، ولكن ستتم إتاحة المزيد من بيانات الاعتماد في المستقبل.

  • لذا، بعد المصادقة، يمكنك استخدام مدير البيانات الجغرافية المكانية للوصول إلى الإمكانات الجغرافية المكانية.

  • ننصحك بشدة بالتحقّق من تغطية VPS في "خرائط Google" أولاً قبل الدمج.

  • لذلك، يجب أن يكون لديك أيضًا إذن الوصول إلى الشبكة عند استخدام الميزة.

  • يعمل XR Geospatial Manager بطريقة مشابهة لمكوّن AR Session الذي يوفّره AR Foundation.

  • لذلك، يتضمّن سمة حالة ثابتة للإشارة إلى توافق النظام وحالة التتبُّع في أداة التتبُّع الجغرافي المكاني.

  • يمكنك تسجيل حدث تغيير الحالة من خلال استدعاء مثل هذا.

    void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
        bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
        if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
            // Handle cloud authentication issues.
        } else if (isInitFailed) {
            // Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
        } else {
            // Iterate runtime state change, and handle accordingly.
        }
    }
    
    private void OnEnable() {
        XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
    }
  • وبعد أن تصبح الحالة الجغرافية المكانية قيد التشغيل، يمكنك استخدام مثيل المدير هذا لجميع الوظائف التالية.

  • أولاً، للتحقّق من توفّر خدمة VPS مع الموقع الجغرافي المحدّد في نظام GPS، نستخدم هنا واجهة برمجة التطبيقات للموقع الجغرافي في Unity للحصول على قيمة GPS ثم التحقّق من توفّر خدمة VPS.

    async Task CheckVPSAvailability(CancellationToken token) {
        var location = Input.location.lastData;
        try {
            var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
                location.latitude, location.longitude);
            token.ThrowIfCancellationRequested();
            if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
                // Invalid coordinates, try with another location.
            } else if (result.status.IsError()) {
                // Handle common OpenXR error: result.status.ToOpenXRStatus()
            }  else if (result.value == XRVPSAvailability.Available)  {
                // You may use this pose to attach geospatial anchors.
                var currentGeospatialPose = new XRGeospatialPose(location);
            }
        }
    }
  • لذا، هذا بديل أساسي إذا كنت لا تريد التحقّق من توافق خدمة تحديد الموقع المرئي من خلال الخريطة، ولكن عليك الخروج للتحقّق من حالة نظام تحديد المواقع العالمي (GPS) الفعلية.

  • بعد ذلك، يمكنك أيضًا تحويل الوضعية بين وضعية Unity والوضعية الجغرافية المكانية من خلال TryLocate.

    // Geospatial Pose -> Unity Pose
    var geospatialPose =
        new XRGeospatialPose(Input.location.lastData);
    if (geospatialManager.TryLocate(
            geospatialPose, out XRPoseResult result)) {
        if (result.IsPositionValid ||
            result.IsPositionTracked) {
            transform.position = result.Pose.position;
        }
        if (result.IsRotationValid ||
            result.IsRotationTracked) {
            transform.rotation = result.Pose.rotation;
        }
    }
    // Unity Pose -> Geospatial Pose
    Pose pose = new Pose(
        transform.position, transform.rotation);
    if (geospatialManager.TryLocate(
          pose, out XRGeospatialPoseResult result)) {
        if (result.IsPositionValid ||
            result.IsRotationValid) {
            // You may use for anchor attachment.
        }
    }
  • وبعد الحصول على النتيجة من عملية التحقّق من VPS أو تحويل الوضعية، يمكنك بعد ذلك إرفاق نقطة الارتكاز المكانية بوضعية جغرافية مكانية معيّنة أو بنوع سطح معروف، مثل التضاريس أو سطح المبنى.

    async void PlaceAnchor(XRGeospatialPose pose) {
        try {
            Result<ARShareableAnchor> anchorResult;
            XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
            if (typeToPlace == XRGeospatialSurfaceType.Default) {
                anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
            } else {
                pose.Altitude = 0;
                anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
            }
            if (anchorResult.status.IsSuccess()) {
                // ARShareableAnchorManager will track the anchor and update it.
            } else {
                // Handle OpenXR failures.
            }
        }
    }
  • وعند دمج كل هذه الميزات معًا، يمكنك إنشاء تجربة مكانية رائعة مع التركيز على العالم الحقيقي.

  • لذا، نضع هنا سهمًا لتوجيه جمهورنا إلى المكان المستهدف في العالم الحقيقي.

  • حسنًا

  • لذا، فإنّ حزمة تطوير البرامج (SDK) لمنصة Android XR ليست الحزمة الوحيدة التي نقدّمها لمطوّري Unity.

  • تتضمّن حزمة تطوير البرامج (SDK) لمنصة Android XR من Google في Unity الآن أيضًا حزمة Android XR Interaction Framework وحزمة Android XR Audio.

  • ويسرّنا جدًا توسيع نطاق حزمة تطوير البرامج (SDK) لنظام Android XR من خلال إتاحة المزيد من الميزات وإدراج المزيد من الكيانات المكانية أيضًا.

الخاتمة والمراجع

  • حسنًا، وصلنا إلى نهاية الجلسة.

  • يمكنك متابعة خطة Unity على الإنترنت لمعرفة الميزات الجديدة التي ستتوفّر قريبًا.

  • يُرجى العِلم أنّنا سنطلق Unity 7، الجيل التالي من Unity، في أوائل العام المقبل.

  • في هذه الأثناء، يمكنك تجربة هذه الأدوات وإنشاء مشروع باستخدام نموذج الواقع المختلط أو الاطّلاع على نموذج مشروع AR Foundation على GitHub.

  • لمزيد من المعلومات حول Spatial Entity ودعم حزمة Unity، يمكنك زيارة الصفحة على موقع مطوّري برامج Android.

  • شكرًا لكم جميعًا.

  • نحن متحمّسون لرؤية ما يمكنك إنشاؤه باستخدام AR Foundation وSpatial Entity على Android XR.

الرمز

مقتطفات الرمز البرمجي

مقتطف C# ‎ في الدقيقة 10:34 في "المثبّتات المحلية والاستمرارية"
async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
    var result = await manager.TryAddAnchorAsync(pose);
    if (result.status.IsError()) {
        // handle error
        return;
    }
    var anchor = result.value;
}
مقتطف C# ‎ في الدقيقة 10:43 في "نقاط الارتساء المحلية والثبات"
void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
    var result = manager.TryRemoveAnchor(anchor.trackableId);
    if (result.status.IsError()) {
        // handle error
        return;
    }
}

void DestroyAnchorComponent(ARAnchor anchor) {
    Destroy(anchor);
}
مقتطف C# ‎ في الدقيقة 11:00 في "كيانات الثقة المحلية والثبات"
async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
    var result = await manager.TrySaveAnchorAsync(anchor);
    if (result.status.IsError()) {
        // handle error
        return;
    }

    // Save this value, then return it as an input parameter
    SerializableGuid guid = result.value;
}
مقتطف C# ‎ في الدقيقة 11:17 في "كيانات الثقة المحلية والثبات"
async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
    var result = await manager.TryLoadAnchorAsync(guid);
    if (result.status.IsError()) {
        // handle error
        return;
    }

    ARAnchor anchor = result.value;
}
مقتطف C# ‎ في الدقيقة 16:45 في فيديو "الإنشاء باستخدام الكيانات المكانية"
void Awake() {
    planeManager = GetComponent<ARPlaneManager>();
    planeManager.enabled = false;
    boundingBoxManager = GetComponent<ARBoundingBoxManager>();
    boundingBoxManager.enabled = false;
    permissionUtil = GetComponent<AndroidXRPermissionUtil>();
}

void OnEnable() {
    StartCoroutine(WaitForPermissions());
}
مقتطف C# ‎ في الدقيقة 16:58 في فيديو "الإنشاء باستخدام الكيانات المكانية"
IEnumerator WaitForPermissions() {
    planeManager.enabled = false;
    boundingBoxManager.enabled = false;

    yield return new WaitUntil(() =>
        permissionUtil.AllPermissionGranted());

    // Enable after granted permissions and
    // restart subsystems.
    planeManager.enabled = true;
    boundingBoxManager.enabled = true;

    // Save permission status.
    permissionGranted = true;
}
مقتطف C# ‎ في الدقيقة 19:12 في فيديو "Geospatial API"
async Task TrySetAuthentication() {
    googleCloudFeature =
        OpenXRSettings.Instance
            .GetFeature<XRGoogleCloudFeature>();
    var result = await googleCloudFeature
        .TrySetAuthenticationAsync(
            strategy, credential);
    if (result.IsSuccess()) {
        // Ready to use for geospatial tracker.
    } else if (result.IsUnsupported())  {
        // Google Cloud feature is not supported
    } else if (result.IsKeylessError()) {
        // Confirm if keyless has been set up properly.
    } else {
        // Handling other common OpenXR errors.
    }
}
مقتطف C# ‎ في الدقيقة 20:24 في فيديو "Geospatial API"
void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
    bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
    if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
        // Handle cloud authentication issues.
    } else if (isInitFailed) {
        // Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
    } else {
        // Iterate runtime state change, and handle accordingly.
    }
}

private void OnEnable() {
    XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
}
مقتطف C# ‎ في الدقيقة 20:38 في فيديو "Geospatial API"
async Task CheckVPSAvailability(CancellationToken token) {
    var location = Input.location.lastData;
    try {
        var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
            location.latitude, location.longitude);
        token.ThrowIfCancellationRequested();
        if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
            // Invalid coordinates, try with another location.
        } else if (result.status.IsError()) {
            // Handle common OpenXR error: result.status.ToOpenXRStatus()
        }  else if (result.value == XRVPSAvailability.Available)  {
            // You may use this pose to attach geospatial anchors.
            var currentGeospatialPose = new XRGeospatialPose(location);
        }
    }
}
مقتطف C# ‎ في الدقيقة 21:03 في فيديو "Geospatial API"
// Geospatial Pose -> Unity Pose
var geospatialPose =
    new XRGeospatialPose(Input.location.lastData);
if (geospatialManager.TryLocate(
        geospatialPose, out XRPoseResult result)) {
    if (result.IsPositionValid ||
        result.IsPositionTracked) {
        transform.position = result.Pose.position;
    }
    if (result.IsRotationValid ||
        result.IsRotationTracked) {
        transform.rotation = result.Pose.rotation;
    }
}
مقتطف C# ‎ في الدقيقة 21:03 في فيديو "Geospatial API"
// Unity Pose -> Geospatial Pose
Pose pose = new Pose(
    transform.position, transform.rotation);
if (geospatialManager.TryLocate(
      pose, out XRGeospatialPoseResult result)) {
    if (result.IsPositionValid ||
        result.IsRotationValid) {
        // You may use for anchor attachment.
    }
}
مقتطف C# ‎ في الدقيقة 21:11 في فيديو "Geospatial API"
async void PlaceAnchor(XRGeospatialPose pose) {
    try {
        Result<ARShareableAnchor> anchorResult;
        XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
        if (typeToPlace == XRGeospatialSurfaceType.Default) {
            anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
        } else {
            pose.Altitude = 0;
            anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
        }
        if (anchorResult.status.IsSuccess()) {
            // ARShareableAnchorManager will track the anchor and update it.
        } else {
            // Handle OpenXR failures.
        }
    }
}