Android XR

איך ליצור תוכן מרחבי ב-Android XR באמצעות Unity

רמקולים

  • לבנה חן

    מהנדס תוכנה

  • Jennifer Stanton

    מהנדס תוכנה בכיר

מידע כללי

מידע על ההרצאה

איך להצמיד ולשמור חוויות תלת-ממדיות בעולם האמיתי באמצעות Unity ו-Android XR. בשיעור הזה נסביר על מסגרת Spatial Entities, על Cloud Anchors ועל Geospatial API, ונדגים איך ליצור אפליקציות שמותאמות להקשר, זוכרות מיקומים פיזיים ומסנכרנות נתונים מרחביים של משתמשים מרובים בין סשנים.

נבחן את הארכיטקטורה שמאחורי ישויות מרחביות, ונבין איך לעגן נכסים דיגיטליים לאובייקטים פיזיים, למשטחים ולמיקומים גיאוגרפיים. בסדנה נלמד תהליכי עבודה מעשיים ב-Unity למיפוי חללים, לשמירת תוכן בין סשנים וליצירת חוויות AR/XR משותפות עם גישה למיקום.

סיכום

  • ‫AR Foundation מספק ממשק API מאוחד לסקריפטים בפלטפורמות XR באמצעות תוספי OpenXR. הוא מאפשר לייצג ולשאול לגבי תכונות בעולם האמיתי, כמו מישורים ורשתות.
  • עוגנים קבועים מייצבים את התוכן הדיגיטלי בסשנים שונים ובהפעלות מחדש של המכשיר. אפשר לשמור אותם באמצעות TrySaveAnchorAsync ולטעון אותם מחדש באמצעות מזהים ייחודיים גלובליים (GUID) שעברו סריאליזציה.
  • המסגרת של ישויות מרחביות מחליפה את התוספים שניתן לעקוב אחריהם כדי לספק תמיכה בפלטפורמות שונות וביצועים טובים יותר למעקב אחרי פריטים כמו תיבות תוחמות וסמנים.
  • רכיבי הניהול צריכים להיות מושבתים עד שמעניקים הרשאות ל-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 כמהנדס תוכנה בכיר.

  • אני עובד בצוות XR Features, ספציפית על AR Foundation ועל החבילות הקשורות שמביאות מציאות רבודה ומציאות משולבת ל-Unity.

  • אני לבנה חן מצוות מנועי המשחקים ב-XR של Google.

  • הצוותים שלנו התמקדו בפיתוח פלאגינים וחבילות שמספקים פונקציונליות XR משופרת ושילוב חלק של מנוע המשחק.

  • אחד האתגרים הכי גדולים שאתם מספרים לנו עליהם הוא שתמיכה בכמה פלטפורמות XR עם אותו בסיס קוד דורשת הרבה עבודה.

  • ‫AR Foundation היא שכבת API ברמה גבוהה של Unity למציאות מורחבת (XR).

  • אתם יכולים לטרגט כמה פלטפורמות XR בלי לשכתב את הקוד באופן משמעותי, בלי לנהל כמה בסיסי קוד, ולקבל API אחד של סקריפטים לתכונות AR בכל פלטפורמה.

  • כך אתם יכולים להתמקד ביצירת האפליקציה, המשחק או החוויה, ו-Unity תטפל בפרטי הפלטפורמה בשבילכם.

  • אחת הדרכים שבהן AR Foundation עושה את זה היא באמצעות תוספים של OpenXR.

  • אלה ממשקי API פתוחים, שהם סטנדרט מקובל בתחום, שהוגדרו על ידי Khronos Group.

  • גם OpenXR יצרה ישויות מרחביות.

  • זו מסגרת שמאפשרת לתוכן דיגיטלי לייצג את העולם הפיזי ולקיים איתו אינטראקציה.

  • ישויות מרחביות מספקות מודל אחיד לייצוג אלמנטים מהעולם האמיתי כאובייקטים דיגיטליים.

  • אני שמח לשתף אתכם במידע עדכני על AR Foundation, כדי שתוכלו להתחיל ליצור חוויות ל-XR.

  • אחר כך אעבור על היכולות של AR Foundation כדי שהתוכן הדיגיטלי שלכם יוכל לקיים אינטראקציה עם העולם האמיתי.

  • אחר כך אעבור על הגדרת הפרויקט, כולל חבילות ותלויות אחרות, כדי שתוכלו ליישם את זה בפרויקטים שלכם.

  • בסיום, אעבור על כמה תכונות ייחודיות ל-Android XR.

התכונות העיקריות של AR Foundation

  • אז אחת מהדרכים שבהן AR Foundation מייצג את העולם האמיתי באופן דיגיטלי היא מישורים.

  • אלה משטחים ישרים בסביבה הפיזית, כמו רצפות, קירות, תקרות ואפילו שולחנות וספות.

  • רשתות הן מבנים תלת-ממדיים שמייצגים את הגיאומטריה של העולם הפיזי.

  • ויש לנו גם דרכים ליצור אינטראקציה עם העולם האמיתי, הטלת קרניים.

  • הם קובעים איפה הקרן מצטלבת עם התוכן הדיגיטלי.

  • אפשר לחשוב על זה כמו על מצביע לייזר, שנותן מידע על המקום שאליו הוא מכוון.

  • יש לנו גם עוגנים, שעוזרים לייצב ולשנות את המיקום של נקודה במרחב.

  • בהמשך המצגת אפרט יותר על עוגנים.

  • לכן, כל ארבעת המאפיינים האלה נחשבים לתכונות של AR Foundation.

  • יש עוד כמה תכונות שלא מוזכרות בשקף הזה.

  • מישורים ונקודות עיגון, באופן ספציפי, נחשבים לאובייקטים שניתן לעקוב אחריהם כי הם מרחיבים את המחלקה ARTrackable, והמנהלים שלהם עוקבים אחר עדכונים מזמן הריצה.

  • אז בואו נתחיל עם מטוסים.

  • למישורים, יש לנו את הרכיב ARPlane, שמזהה משטחים שטוחים בזמן אמת.

  • יש להם תוויות סמנטיות שאפשר לשלוח להן שאילתות כדי לדעת אם המישור הוא רצפה, שולחן, קיר וכו'.

  • למישורים יש גם גבולות דינמיים, כך שככל שהמשתמש נע בעולם האמיתי ורואה יותר מהמשטחים, גבולות המישור מתרחבים, מתמזגים ומתעדנים באופן דינמי בזמן אמת.

  • אנחנו יכולים גם לצרף למטוס קוליידר רשת כדי לטפל בפיזיקה.

  • כאן אפשר לראות דוגמה לזיהוי מישור.

  • זוהי סצנה של הטלת קרן מדגימות של AR Foundation שפועלת במכשיר Android XR.

  • הוא מזהה פוליגונים דינמיים דו-ממדיים בזמן אמת.

  • כדי ליצור אפליקציה עם הפונקציונליות הזו, אתם יכולים לפעול לפי המדריך שלנו להגדרת פרויקט או להשתמש באחת מהדוגמאות או התבניות שלנו.

  • השלב הבא הוא רשתות.

  • רשתות הן תכונת AR שמספקת רשתות תלת-ממדיות של הסביבה.

  • אנחנו יכולים לצרף קוליידר רשת לרשתות שנוצרו, וכך לאפשר לתוכן הדיגיטלי שלכם לקיים אינטראקציה עם אובייקטים בעולם האמיתי.

  • רשתות מאפשרות הסתרה משכנעת של אובייקטים.

  • כך, אובייקט וירטואלי יכול להופיע מאחורי אובייקט פיזי.

  • אם האובייקט הדיגיטלי יכול לנוע במרחב, אתם יכולים להשתמש באותה גיאומטריה כדי למצוא נתיב שמונע התנגשות עם אובייקטים בעולם האמיתי.

  • השלב הבא הוא הטלת קרניים.

  • הטלת קרניים מקרינה קרניים וירטואליות לתוך הסצנה התלת-ממדית כדי לחפש נקודות חיתוך, בלי שתצטרכו להתעסק עם המתמטיקה המורכבת.

  • קרן מוקרנת יכולה להצטלב עם כמה אובייקטים תלת-ממדיים בסביבה.

  • אפשר להגדיר את הטלת הקרן כך שתפגע רק בסוגים מסוימים של תוכן דיגיטלי.

  • לדוגמה, אפשר להגדיר שהיא לא תפגע במישורים ותצטלב רק עם רשתות.

הגדרת חבילות ויחסי תלות

  • עכשיו נסתכל על החבילות הרלוונטיות.

  • כל החבילות האלה פועלות יחד כדי לתקשר זו עם זו וליצור חוויית XR מלאה.

  • כמו שציינו, AR Foundation מטפל בתכונות כמו מישורים ונקודות עיגון.

  • הפלאגין של OpenXR מטפל בממשקי API מקוריים בפלטפורמות XR שונות, אז כדאי להשתמש בחבילה הזו אם המכשיר שלכם משתמש ב-OpenXR.

  • אפשר לשלב את הפלאגין של OpenXR עם חבילת OpenXR Spatial Entities כדי לגשת ספציפית לתוספים של ישויות מרחביות, ובהמשך נרחיב על כך.

  • אם אתם יודעים שתטרגטו מכשירי Android XR באופן ספציפי, כמו משקפי XR ומשקפי XR עם חיבור חוטי, אתם צריכים את חבילת Unity OpenXR Android XR.

  • מכיוון שכל זה פועל לפי תבנית הפלאגין, ההשפעה על הקוד שלכם אמורה להיות מינימלית.

  • לא כל התכונות זמינות בכל החבילות של AR Foundation.

  • לדוגמה, אם תסתכלו על הטבלה הזו, תראו שכרגע אי אפשר להשתמש ב-meshing בחבילת Unity OpenXR Spatial Entities.

  • הכלי XR Plug-in Management מאפשר לכם לנהל את התכונות של OpenXR שנבחרו בפרויקט.

  • לכן, אם אתם בעורך של Unity, אתם צריכים לעבור אל Edit (עריכה), Project Settings (הגדרות הפרויקט), ואז XR Plug-in Management (ניהול פלאגינים של XR) יופיע בסרגל הצד הימני.

  • כאן אפשר למצוא תכונות וקבוצות של תכונות ב-OpenXR, ולבחור או לבטל את הבחירה בתכונות ובקבוצות של תכונות שרוצים לכלול בגרסה.

  • לדוגמה, בצילום המסך הזה אנחנו רואים את כל התכונות שמגיעות עם חבילת Android XR OpenXR.

  • ואז אפשר לשלב אותם עם ישויות מרחביות, למשל, אם רוצים.

  • זה החלון של Package Manager.

  • הדגשתי כמה מהחבילות שעשויות להופיע בהגדרה אופיינית של פרויקט XR.

  • כמו שאפשר לראות, יש לנו את AR Foundation, שכבר הוזכר.

  • יש לנו גם את הפלאגין OpenXR.

  • יש לנו את חבילת Android XR.

  • הדגשתי גם כמה פלטפורמות אחרות, כי בהחלט אפשר ליצור פרויקט שמתקמפל לכמה פלטפורמות.

  • בפינה השמאלית התחתונה יש גם חבילות אחרות.

  • ‫Composition Layers, שעובדות עם מכשירי OpenXR; ‏Core Utils, שמאוד שימושיות לכל מה שקשור ל-XR; וגם XR Hands ו-XR Interaction Toolkit כדי לקבל את הקלט, שזה די חיוני.

  • השלב הבא הוא אימות הפרויקט.

  • אז שוב, זה חלק מניהול הפלאגינים של XR.

  • אימות הפרויקט יכול לזהות תכונות כפולות, וגם בעיות אחרות בפרויקט שצריך לתקן כדי להפעיל אותו.

  • אבל בצילום המסך הזה הדגשתי את התכונות הכפולות.

  • אז מה שזה בעצם אומר זה ששתי תכונות זהות, כמו למשל, אני חושב שיש לנו כאן עוגנים, אולי מישורים ו-raycasts.

  • המשתמש בחר לכלול כפילויות של התכונות האלה מכמה חבילות, והוא פשוט מתבקש לבחור אחת מהן.

עוגנים מקומיים וקביעות

  • זה מביא אותנו לעוגנים מקומיים ולעקביות.

  • עוגנים מבטיחים שהתוכן הדיגיטלי יישאר במיקומים הרצויים בסביבה, בלי קשר לשינויים במצב המעקב של סשן ה-AR.

  • פלטפורמות AR מעדכנות באופן אוטומטי את המיקומים של נקודות העיגון לאורך זמן כדי לוודא שהן נשארות במיקום עקבי. נקודות העיגון הן הדרך הטובה ביותר לוודא שהתוכן נשאר במקום אם מתרחקים מנקודת העיגון ואז חוזרים אליה.

  • ומה קורה כשהמשתמש סוגר את האפליקציה, מפעיל אותה מחדש מאוחר יותר וחוזר אליה בסשן נפרד?

  • עוגנים קבועים מאפשרים לשמור עוגנים בסשן AR ואז לטעון אותם בסשנים הבאים.

  • הם נשמרים גם אחרי סגירת האפליקציה והפעלה מחדש של המכשיר.

  • בתמונה הזו מוצגת דוגמה לעוגנים קבועים בפרויקט AR Foundation Samples.

  • בסצנה לדוגמה יש תפריט עם כל הפונקציות שנתמכות בפלטפורמה הזו, כמו שמירה וטעינה של עוגנים.

  • זה מביא אותנו למחזור החיים של עוגנים קבועים.

  • קודם יוצרים עוגן באופן מקומי, כך שהוא עדיין לא נשמר בשום מקום, לא נשמר באחסון מתמיד, אלא רק עוגן מקומי.

  • ואז לשמור אותו באחסון.

  • אחרי זה, אתם יכולים להפעיל מחדש את האפליקציה ולטעון אותה מהאחסון.

  • בחלק מהפלטפורמות, כולל Android XR, אפשר גם למחוק או לבטל את השמירה של נקודות העיגון.

  • ספק הישויות המרחביות תומך בטעינה אוטומטית של כל נקודות העיגון השמורות, כך שלא צריך לבקש ידנית כל נקודת עיגון לפי המזהה שלה.

  • בהגדרות של XR Plug-in Management, אתם יכולים לבחור באפשרות Automatically Load Saved Anchors (טעינה אוטומטית של עוגנים שמורים) בתכונה Spatial Entities: Anchors (ישויות מרחביות: עוגנים).

  • כדי לשמור עוגן, צריך רק כמה שורות קוד.

  • קודם כל, מתחילים בכלי העריכה של 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;
    }
  • אתם מעבירים עוגן AR כקלט.

  • הפונקציה הזו מחזירה 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 שעבר סריאליזציה מקודם.

  • התוצאה תהיה עוגן AR.

  • וזה פחות או יותר הכול.

  • הפונקציות האלה מאפשרות לנהל בקלות גם עוגנים מקומיים וגם עוגנים קבועים.

  • לכן, מעקב אחר עוגנים הוא משימה יקרה למדי ברוב פלטפורמות ה-AR.

  • כשעובדים עם נקודות עיגון, כדאי לפעול לפי השיטות המומלצות הבאות: להימנע מיצירת כמה נקודות עיגון קרובות מאוד זו לזו, לבדוק אם אפשר להשתמש בנקודת עיגון קרובה במקום ליצור נקודה נוספת, להסיר נקודות עיגון כשכבר לא משתמשים בהן, ואם מפעילים תכונת AR אחרת כדי לחשב את התנוחה הרצויה לנקודת עיגון, לבדוק אם אפשר להשבית את התכונה הזו אחרי שנקודת העיגון נוצרה בהצלחה.

  • עכשיו אעביר את רשות הדיבור ללבנה.

Android XR SDK for Unity

  • תודה, כנרת.

  • עכשיו אסביר לכם מה התרומה של Google לתהליך של Android XR ב-Unity.

  • אז בנוסף לפלאגינים של Unity OpenXR שג'ניפר הציגה עד עכשיו, Google מספקת את Android XR SDK ל-Unity עם יכולות נוספות שזמינות בפלטפורמת Android XR.

  • ה-SDK הזה מכיל הרבה תכונות וחבילות, ובהרצאה הזו נתמקד בחבילת Android XR Extension for Unity.

  • לכן, בדומה ל-OpenXR Android XR ולישויות מרחביות של OpenXR, חבילת Android XR Extension for Unity היא למעשה ספק OpenXR.

  • הארכיטקטורה של החבילה הזו נראית ככה, והם יכולים לעבוד במקביל או בנפרד.

  • לכן, כמו כל ספק OpenXR אחר, החבילה של Google מבוססת ישירות על ממשק OpenXR רגיל.

  • לכן, אנחנו מציגים כאן כמה תכונות להשוואה בין כל הספקים האחרים.

  • כך תוכלו להחליט מתי ולמה לבחור באפשרות אחת על פני השנייה.

  • לכן, יכול להיות שיש לכם שאלה לגבי הסמן של הישות הניתנת למעקב והישות המרחבית שמוצג בטבלה הזו.

  • אז הנה הערה קטנה: למי שכבר פיתחו אפליקציות וחוויות ב-Android XR בעבר, סיפקנו את התכונות האלה דרך התוספים שניתן לעקוב אחריהם, והם פועלים רק ב-Android XR.

  • ואז, כמו שג'ניפר ציינה, עבדנו כקבוצה פתוחה של OpenXR, ואז פרסמנו את Spatial Entities Extension בצד ימין וסיפקנו חוויה עקבית בפלטפורמות שונות.

  • כרגע אנחנו מוציאים משימוש את התוסף Trackable לטובת מסגרת העבודה Spatial Entities.

  • האפשרות השנייה לא רק משפרת את הביצועים, אלא גם תומכת בפלטפורמות שונות.

איך נעזרים בישויות מרחביות

  • עכשיו נבחן מקרוב את הישויות המרחביות.

  • אז בנוסף למה שג'ניפר הזכירה לגבי המישורים, הטלת הקרניים והעוגנים, אתם יכולים למצוא את התכונה הזו גם בספקי ישויות מרחביות, כמו סמנים, שיכולים לזהות ולפענח ברקודים דו-ממדיים רגילים ולעקוב אחרי המיקום שלהם במרחב תלת-ממדי, והתמונה תזהה גרפיקה דו-ממדית מוכרת ותעקוב אחריה במרחב תלת-ממדי.

  • ואז התיבה התוחמת, שתזהה את האובייקט הפיזי, כמו מקלדת, מחשב נייד או עכבר, ותעקוב אחרי התיבה התוחמת שלהם בתנוחה תלת-ממדית.

  • בדוגמה הבאה נגדיר את התכונה "תיבה תוחמת" שכלולה בחבילת התוספים של Google.

  • לכן, התצוגה הזו די זהה לכל התכונות של OpenXR.

  • אז אתם רק צריכים לעבור קודם לפלטפורמת Android XR, ואז להפעיל את ספק OpenXR ולבחור את התכונה של OpenXR שאתם רוצים להשתמש בה. לדוגמה, התכונה של התיבה התוחמת של הישות המרחבית הוצגה כאן. אחר כך צריך לתקן את הבעיות באימות הפרויקט.

  • הוא יעזור לכם למצוא את כל יחסי התלות שנדרשים לתכונה מסוימת, ואז לפתור את ההתנגשויות שנגרמות כתוצאה מכך שכמה תכונות תורמות לאותה תת-מערכת.

  • לפעמים צריך לבחור רק תכונה אחת אם רוצים להשתמש, למשל, בעוגן, במישור או בתיבה תוחמת (bounding box) כאן.

  • ולבסוף, אתם יכולים פשוט לבנות את הסצנה לדוגמה או את סצנת הבדיקה.

  • כדי לגשת לאובייקט שניתן למעקב בזמן הריצה, אפשר פשוט להוסיף את רכיב הניהול של התיבה התוחמת של AR, הוא דומה לרכיב של מנהל העוגנים של AR, ואז להשתמש בממשק של 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, אבל להשתמש בנתוני Street View בחוץ כדי לספק תוצאות מעקב מדויקות הרבה יותר.

  • יכול להיות שחלק מכם כבר מכירים את התצוגה הזו אם יש לכם ניסיון קודם עם התכונה הגיאו-מרחבית של ARCore.

  • לכן, כדי לגשת ל-Geospatial API ב-Android XR, קודם צריך להתחבר לקצה העורפי שמתארח בפלטפורמת Google Cloud.

  • מכיוון שה-backend הגיאוספציאלי מופעל בפועל על ידי שירות ARCore ב-Google Cloud, אתם יכולים לפעול בדיוק לפי אותו שלב כדי להגדיר את הפרויקט שלכם ב-Google Cloud עם גישה ל-ARCore API.

  • כל זה יאפשר להשתמש בתכונה של Android XR Google Cloud שמסופקת על ידי חבילת התוספים שלנו.

  • אחרי שמפעילים את Geospatial API ומקבלים את מפתח ה-API מהפרויקט ב-Google Cloud, אפשר להפעיל את התכונה הזו ולהגדיר את האימות דרך תפריט ההגדרות של OpenXR שמוצג כאן. לחלופין, אפשר להגדיר אותו באופן ידני דרך ה-API לכתיבת סקריפטים שנקרא 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 תומכת כרגע רק באימות באמצעות מפתח API, אבל בעתיד תהיה תמיכה באישורים נוספים.

  • אחרי האימות, אתם יכולים להשתמש במנהל הנתונים הגיאוגרפיים כדי לגשת ליכולות הגיאוגרפיות.

  • לפני השילוב, מומלץ מאוד לבדוק במפות Google את הכיסוי של VPS.

  • לכן, כדי להשתמש בתכונה, צריך גם גישה לרשת.

  • ה-XR Geospatial Manager פועל באופן דומה לרכיב AR Session שמסופק על ידי AR Foundation.

  • לכן, הוא כולל מאפיין סטטי של מצב כדי לציין את תמיכת המערכת ואת מצב המעקב של הכלי למעקב גיאוגרפי.

  • אפשר לרשום אירוע של שינוי מצב באמצעות פונקציית קריאה חוזרת (callback) כזו.

    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 הנתון, אנחנו משתמשים ב-location API של 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);
            }
        }
    }
  • אז בעצם, אם אתם לא רוצים לבדוק את התמיכה ב-VPS דרך המפה, אתם יכולים להשתמש באפליקציה הזו, אבל תצטרכו לצאת החוצה כדי לבדוק את הסטטוס של ה-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.
            }
        }
    }
  • כשמשלבים את כל אלה, אפשר ליצור חוויה מרחבית קסומה באמת, שבה העולם האמיתי נמצא במרכז.

  • לכן, אנחנו מציבים כאן חץ כדי להנחות את הקהל שלנו למקום המטורגט בעולם האמיתי.

  • אוקיי.

  • לכן, Android XR SDK היא לא החבילה היחידה שסיפקנו למפתחי Unity.

  • ערכת Android XR SDK של Google ל-Unity כוללת עכשיו גם את Android XR Interaction Framework ואת חבילת Android XR Audio.

  • אנחנו גם שמחים להרחיב את Android XR SDK עם תמיכה בתכונות נוספות, כולל עוד ישויות מרחביות.

סיכום ומשאבים

  • אוקיי, אז אנחנו מתקרבים לסוף הפגישה.

  • אפשר לעקוב אחרי מפת הדרכים של Unity באינטרנט כדי לראות מה צפוי בהמשך.

  • חשוב לזכור: בתחילת השנה הבאה נשיק את Unity 7, הדור הבא של Unity.

  • בינתיים, אתם יכולים לנסות את הכלים האלה וליצור פרויקט באמצעות התבנית של המציאות המשולבת, או לעיין בפרויקט לדוגמה של AR Foundation ב-GitHub שלנו.

  • כדי לקבל מידע נוסף על Spatial Entity ועל התמיכה שלנו בחבילת Unity, אפשר להיכנס לדף באתר למפתחי Android.

  • תודה לכולם.

  • אנחנו כבר ממש סקרנים לראות מה תיצרו עם AR Foundation ועם הישות המרחבית ב-Android XR.

קוד

קטעי קוד

קטע קוד ב-C# ‎ בדקה 10:34 בסרטון "Local anchors and persistence"
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 בסרטון "Local anchors and persistence"
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 בסרטון "Local anchors and persistence"
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 בסרטון "Local anchors and persistence"
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 בסרטון "Building with spatial entities"
void Awake() {
    planeManager = GetComponent<ARPlaneManager>();
    planeManager.enabled = false;
    boundingBoxManager = GetComponent<ARBoundingBoxManager>();
    boundingBoxManager.enabled = false;
    permissionUtil = GetComponent<AndroidXRPermissionUtil>();
}

void OnEnable() {
    StartCoroutine(WaitForPermissions());
}
קטע קוד ב-C# ‎ בדקה 16:58 בסרטון "Building with spatial entities"
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.
        }
    }
}