שימוש בעוגנים גיאו-מרחביים כדי למקם תוכן מהעולם האמיתי ב-Android SDK (Kotlin/Java)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

התכונה Earth.getGeospatialPose() מספקת דרך נוספת לקבוע את קו הרוחב וקו האורך על ידי המרה של מיקום AR למיקום גיאו-מרחבי.

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

הפונקציה Earth.getPose() ממירה מיקום אופקי, גובה וסיבוב קוואטרניון שצוינו על פני כדור הארץ ביחס למסגרת קואורדינטות מזרח-מעלה-דרום לתנוחת 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. לוחצים על החץ חזרה בחלונית הפרויקט ובוחרים בתפריט פעולות נוספות.

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

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

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

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

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

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

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

הפונקציה GeospatialPose.getEastUpSouthQuaternion() מחלצת את הכיוון מתנוחה גיאוגרפית ומפיקה קוואטרניון שמייצג את מטריצת הסיבוב שממירה וקטור מהיעד למערכת הקואורדינטות מזרח-מעלה-דרום (EUS). X+ מצביע למזרח, Y+ מצביע למעלה ו-Z+ מצביע לדרום. הערכים נכתבים בסדר {x, y, z, w}.

עוגנים של WGS84

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

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

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

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

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

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

יצירת העוגן

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

Java

if (earth != null && earth.getTrackingState() == TrackingState.TRACKING) {
  Anchor anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw);

  // Attach content to the anchor specified by geodetic location and pose.
}

Kotlin

if (earth.trackingState == TrackingState.TRACKING) {
  val anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw
    )

  // Attach content to the anchor specified by geodetic location and pose.
}

עוגנים של שטח

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

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

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

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

אפשר לבחור איך האפליקציה תזהה מטוסים באמצעות Config.PlaneFindingMode.

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

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

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

Java

final ResolveAnchorOnTerrainFuture future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    /* altitudeAboveTerrain= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Kotlin

var future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    altitudeAboveTerrain,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

מה יהיה העתיד?

ל-Future יהיה FutureState משויך.

מדינה תיאור
FutureState.PENDING הפעולה עדיין בהמתנה.
FutureState.DONE הפעולה הושלמה והתוצאה זמינה.
FutureState.CANCELLED הפעולה בוטלה.

בודקים את מצב הצמדת התצוגה של התוצאה 'עתיד'.

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

Java

switch (terrainAnchorState) {
  case SUCCESS:
    // A resolving task for this Terrain anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Kotlin

when (state) {
  TerrainAnchorState.SUCCESS -> {
    // A resolving task for this Terrain anchor has finished successfully.
  }
  TerrainAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  TerrainAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  TerrainAnchorState.ERROR_INTERNAL -> {
    // The Terrain anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

עוגנים לגג

מודעות עוגן ב-Hero על גגות

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

יצירת ציון 'גג' באמצעות ה-API האסינכרוני החדש

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

כדי ליצור ולמקם ציון 'גג', קוראים לפונקציה Earth.resolveAnchorOnRooftopAsync(). בדומה למיקומי ציון בשטח, תוכלו גם לגשת לFutureState של העתיד. לאחר מכן אפשר לבדוק את התוצאה העתידית כדי לגשת אל Anchor.RooftopAnchorState.

Java

final ResolveAnchorOnRooftopFuture future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    /* altitudeAboveRooftop= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Kotlin

var future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    altitudeAboveRooftop,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

בדיקת סטטוס העתיד

לעתיד יהיה FutureState משויך, ראו בטבלה שלמעלה.

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

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

Java

switch (rooftopAnchorState) {
  case SUCCESS:
    // A resolving task for this Rooftop anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API.
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Kotlin

when (state) {
  RooftopAnchorState.SUCCESS -> {
    // A resolving task for this Rooftop anchor has finished successfully.
  }
  RooftopAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  RooftopAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  RooftopAnchorState.ERROR_INTERNAL -> {
    // The Rooftop anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

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