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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • כשמשתמשים בגיאומטריה של Streetscape, כדאי להשתמש ב-hit-test כדי לצרף תוכן לבניין.
  • יש עדיפות לעוגנים בפני שטח או לגג על פני עוגנים מסוג 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. מציינים את הפרויקט שרוצים להכיל את הסמן ולוחצים על Save (שמירה).

  6. בשדה כותרת של הסמן, נותנים שם לסמן.

  7. לוחצים על החץ חזרה בחלונית הפרויקט ובוחרים בתפריט פעולות נוספות.

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

יצירת מודעות עוגן

אחרי שמזינים את קווי הרוחב, קו האורך, הגובה והסיבוב, משתמשים ב-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

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

יצירת עוגן לפני שטח באמצעות Async API החדש

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

העוגן לא יהיה מוכן מיד וצריך להיפתר. לאחר פתרון הבעיה, היא תהיה זמינה ב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;
}

בדיקת מצב ההבטחה

להבטחה יהיה PromiseState משויך.

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

בדיקת מצב העוגן של פני השטח בתוצאת Promise

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

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;
}

דיבלים לגגות

עוגנים לגג גיבורים

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

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

העוגן לא יהיה מוכן מיד וצריך להיפתר.

כדי ליצור עוגן בגג ולהציב אותו, יש להפעיל את המספר ARAnchorManagerExtensions.resolveAnchorOnRooftopAsync(). באופן דומה לעוגנים בפני שטח, ניתן לגשת גם אל PromiseState של 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 משויך, ראו טבלה למעלה.

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

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

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;
}

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