שימוש בעוגנים גיאו-מרחביים כדי למקם תוכן מהעולם האמיתי ב-Unity

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

סוגי עוגנים גיאו-מרחביים

יש שלושה סוגים של עוגנים גיאו-מרחביים, וכל אחד מהם מטפל בגובה בצורה שונה:

  1. עוגנים של WGS84:
    עוגנים של WGS84 מאפשרים למקם תוכן תלת-ממדי בכל קו רוחב, קו אורך וגובה נתונים.

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

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

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

דרישות מוקדמות

לפני שממשיכים, חשוב להפעיל את Geospatial API.

הצבת עוגנים גיאו-מרחביים

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

יצירת עוגן מבדיקת היתקלות

אפשר גם ליצור עוגן גיאו-מרחבי מתוצאת בדיקת היעד. משתמשים בתנוחה מהבדיקה להיט וממירים אותה ל-GeospatialPose. אפשר להשתמש בו כדי להציב כל אחד מ-3 סוגי הווידג'טים של עוגנים שמפורטים למעלה.

אחזור תנוחה גיאו-מרחית מתנוחה ב-AR

AREarthManager.Convert(Pose) מספק דרך נוספת לקבוע את קו הרוחב ואת קו האורך על ידי המרת תנוחת AR לתנוחה גיאוגרפית.

אחזור תנוחה ל-AR מתנוחה גיאו-מרחית

הפונקציה AREarthManager.Convert(GeospatialPose) ממירה מיקום אופקי, גובה וסיבוב קוואטרניון שצוינו בכדור הארץ ביחס למסגרת קואורדינטות מזרח-מעלה-דרום לתנוחת AR ביחס לקואורדינטות העולם של GL.

בחירת השיטה שמתאימה לתרחיש לדוגמה

לכל שיטה ליצירת עוגן יש יתרונות וחסרונות שחשוב לזכור:

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

חישוב קווי הרוחב והאורך של מיקום

יש שלוש דרכים לחשב את קו הרוחב ואת קו האורך של מיקום:

  • אתם יכולים להשתמש ב-Geospatial Creator כדי להציג את העולם ולהוסיף לו תוכן תלת-ממדי בלי שתצטרכו להגיע פיזית למיקום מסוים. כך תוכלו למקם תוכן תלת-ממדי עשיר ויזואלית באמצעות מפות Google בכלי העריכה של Unity. קו הרוחב, קו האורך, הסיבוב והגובה של התוכן יחושבו באופן אוטומטי.
  • שימוש במפות Google
  • משתמשים ב-Google Earth. חשוב לדעת: כשמקבלים את הקואורדינטות האלה באמצעות Google Earth, בניגוד למפות Google, טווח השגיאה הוא עד כמה מטרים.
  • מעבר למיקום הפיזי

שימוש במפות Google

כדי לקבל את קו הרוחב ואת קו האורך של מיקום באמצעות מפות Google:

  1. נכנסים למפות Google במחשב.

  2. עוברים אל שכבות > אפשרויות נוספות.

  3. משנים את סוג המפה ללוויין ומבטלים את הסימון של התיבה תצוגת כדור הארץ בפינה הימנית התחתונה של המסך.

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

  4. במפה, לוחצים לחיצה ימנית על המיקום ובוחרים את קו הרוחב/האורך כדי להעתיק אותו ללוח.

שימוש ב-Google Earth

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

כדי לקבל את קו הרוחב ואת קו האורך של מיקום מסוים באמצעות Google Earth:

  1. נכנסים ל-Google Earth במחשב.

  2. עוברים לתפריט ההמבורגר ובוחרים באפשרות סגנון המפה.

  3. משביתים את המתג בניינים בתלת-ממד.

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

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

  6. בשדה Title של סמן המיקום, מזינים שם לסמן המיקום.

  7. לוחצים על החץ לאחור בחלונית הפרויקט ובוחרים בתפריט More Actions (פעולות נוספות).

  8. בתפריט, בוחרים באפשרות ייצוא כקובץ KML.

קובץ KLM מדווח על קו הרוחב, קו האורך והגובה של סמליל מקום בתג <coordinates>, מופרדים בפסיקים, באופן הבא:

<coordinates>-122.0755182435043,37.41347299422944,7.420342565583832</coordinates>

אין להשתמש בקווי הרוחב והאורך מהתגים <LookAt>, שמציינים את מיקום המצלמה ולא את המיקום.

מעבר למיקום הפיזי

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

אחזור הקווטרניון של הסיבוב

הפונקציה GeospatialPose.EunRotation מחלצת את הכיוון מתנוחה גיאוגרפית ומפיקה קוואטרניון שמייצג את מטריצת הסיבוב שממירה וקטור מהיעד למערכת הקואורדינטות מזרח-מעלה-צפון (EUN). X+ מצביע למזרח, Y+ מצביע למעלה, הרחק מהכבידה, ו-Z+ מצביע לצפון.

עוגנים של WGS84

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

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

הצבת עוגן WGS84 בעולם האמיתי

חישוב הגובה של מיקום

יש כמה דרכים לקבוע את הגובה של מיקום מסוים לצורך הצבת עוגנים:

  • אם מיקום הצ'אט מקובע קרוב פיזית למשתמש, אפשר להשתמש בגובה שדומה לגובה של המכשיר של המשתמש.
  • אחרי שמקבלים את קו הרוחב ואת קו האורך, משתמשים ב-Elevation API כדי לקבל גובה על סמך המפרט EGM96. צריך להמיר את הגובה של Maps API EGM96 ל-WGS84 כדי להשוות אותו לגובה של GeospatialPose. אפשר לעיין ב-GeoidEval, שיש לו גם שורת פקודה וגם ממשק HTML. כברירת מחדל, Maps API מדווח על קו הרוחב וקו האורך בהתאם למפרט WGS84.
  • אפשר לקבל את קו הרוחב, קו האורך והגובה של מיקום מסוים מ-Google Earth. כך תהיה לכם מרווח שגיאה של עד כמה מטרים. משתמשים בקווי הרוחב, האורך והגובה מהתגים <coordinates>, ולא מהתגים <LookAt>, בקובץ ה-KML.
  • אם יש עוגן קיים בקרבת מקום וגם אם אתם לא נמצאים במורד תלול, יכול להיות שתוכלו להשתמש בגובה מ-GeospatialPose של המצלמה בלי להשתמש במקור אחר, כמו Maps API.

יצירת העוגן

אחרי שמקבלים את קו הרוחב, קו האורך, הגובה והקוואטרניון של הסיבוב, משתמשים ב-ARAnchorManagerExtensions.AddAnchor() כדי לקשר את התוכן לקואורדינטות גיאוגרפיות שציינתם.

if (earthTrackingState == TrackingState.Tracking)
{
  var anchor =
      AnchorManager.AddAnchor(
          latitude,
          longitude,
          altitude,
          quaternion);
  var anchoredAsset = Instantiate(GeospatialAssetPrefab, anchor.transform);
}

עוגנים של פני השטח

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

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

הגדרת מצב חיפוש המטוס

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

הערה: עוגנים של פני השטח מושפעים מ-Horizontal ומ-Horizontal | Vertical

בתפריט הנפתח Detection Mode (מצב זיהוי) בוחרים את מצב הזיהוי:

יצירת עוגן של Terrain באמצעות ה-API החדש של Async

כדי ליצור ולמקם עוגן של פני השטח, קוראים לפונקציה ARAnchorManagerExtensions.resolveAnchorOnTerrainAsync().

ה-anchor לא יהיה מוכן באופן מיידי, וצריך להמתין עד שהוא יתעדכן. אחרי שהבעיה תיפתר, היא תהיה זמינה בResolveAnchorOnTerrainPromise.

public GameObject TerrainAnchorPrefab;

public void Update()
{
    ResolveAnchorOnTerrainPromise terrainPromise =
        AnchorManager.ResolveAnchorOnTerrainAsync(
            latitude, longitude, altitudeAboveTerrain, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckTerrainPromise(terrainPromise));
}

private IEnumerator CheckTerrainPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.TerrainAnchorState == TerrainAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(TerrainAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

בדיקת הסטטוס של ההבטחה

ל-Promise יהיה PromiseState משויך.

מדינה תיאור
Pending הפעולה עדיין בהמתנה.
Done הפעולה הושלמה והתוצאה זמינה.
Cancelled הפעולה בוטלה.

בדיקת מצב העוגן של Terrain בתוצאה של Promise

הערך TerrainAnchorState שייך לפעולה האסינכרונית והוא חלק מהתוצאה הסופית של Promise.

switch (result.TerrainAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case TerrainAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case TerrainAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case TerrainAnchorState.ErrorInternal:
        // The Terrain anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

עוגנים לגג

תמונה ראשית – עוגנים על הגג

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

יצירת ציון 'גג' באמצעות ה-API החדש של Async

ה-anchor לא יהיה מוכן מיד, וצריך להמתין עד שהוא יתעדכן.

כדי ליצור ולמקם ציון 'גג', מקישים על ARAnchorManagerExtensions.resolveAnchorOnRooftopAsync(). בדומה למיקומי ציון ב-Terrain, תהיה לכם גם גישה ל-PromiseState של ה-Promise. לאחר מכן תוכלו לבדוק את התוצאה של Promise כדי לגשת ל-RooftopAnchorState.

public GameObject RooftopAnchorPrefab;

public void Update()
{
    ResolveAnchorOnRooftopPromise rooftopPromise =
        AnchorManager.ResolveAnchorOnRooftopAsync(
            latitude, longitude, altitudeAboveRooftop, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckRooftopPromise(rooftopPromise));
}

private IEnumerator CheckRooftopPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.RooftopAnchorState == RooftopAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(RooftopAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

בדיקת הסטטוס של ההבטחה

ל-Promise יהיה PromiseState משויך, ראו בטבלה שלמעלה.

בדיקת מצב העוגן של Rooftop בתוצאה של Promise

הערך RooftopAnchorState שייך לפעולה האסינכרונית והוא חלק מהתוצאה הסופית של Promise.

switch (result.RooftopAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case RooftopAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case RooftopAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case RooftopAnchorState.ErrorInternal:
        // The Rooftop anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

המאמרים הבאים