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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

מקבלים את הקווטרניון הסיבובי

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

עוגנים ל-WGS84

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

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

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

איך לקבוע את הגובה של מיקום מסוים

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

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

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

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

float eus_quaternion_4[4] = {qx, qy, qz, qw};
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArAnchor* earth_anchor = NULL;
    ArStatus status = ArEarth_acquireNewAnchor(ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude,
        eus_quaternion_4, &earth_anchor);

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

דיבלים לשטח

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

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

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

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

יש להשתמש ב-ArPlaneFindingMode כדי לבחור איך האפליקציה מזהה מטוסים.

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

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

העוגן לא יהיה מוכן מיד וצריך להיפתר. לאחר פתרון הבעיה, היא תהיה זמינה בArResolveAnchorOnTerrainFuture.

בודקים את מצב העוגן של פני השטח באמצעות ArResolveAnchorOnTerrainFuture_getResultTerrainAnchorState(). כדי לתקן את העוגן שטופל, משתמשים ב-ArResolveAnchorOnTerrainFuture_acquireResultAnchor().

float eus_quaternion_4[4] = {qx, qy, qz, qw};
void* context = NULL;
ArResolveAnchorOnTerrainCallback callback = NULL;
ArResolveAnchorOnTerrainFuture* future = NULL;
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArStatus status = ArEarth_resolveAnchorOnTerrainAsync(
        ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude_above_terrain, eus_quaternion_4,
        context, callback, &future);
  }
}

בדיקת מצב העתיד

לעתיד יהיה ArFutureState משויך.

ארץ התיאור
AR_FUTURE_STATE_PENDING הפעולה עדיין בהמתנה.
AR_FUTURE_STATE_DONE הפעולה הושלמה והתוצאה זמינה.
AR_FUTURE_STATE_CANCELLED הפעולה בוטלה.

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

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

switch (terrain_anchor_state) {
  case AR_TERRAIN_ANCHOR_STATE_SUCCESS:
    // A resolving task for this anchor has been successfully resolved.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the
    // Geospatial API.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/c/group/ar-anchor#:~:text=from%20this%20error.-,AR_TERRAIN_ANCHOR_STATE_ERROR_NOT_AUTHORIZED,-The%20authorization%20provided
    // for troubleshooting steps.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_INTERNAL:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}

דיבלים לגגות

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

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

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

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

כדי ליצור עוגן בגג ולהציב אותו, יש להפעיל את המספר ArEarth_resolveAnchorOnRooftopAsync(). באופן דומה לעוגנים בפני שטח, תהיה לכם גישה גם ל-ArFutureState של העתיד. לאחר מכן תוכלו לבדוק את התוצאה העתידית כדי לגשת אל ArRooftopAnchorState.

יש להשתמש ב-ArEarth_resolveAnchorOnRooftopAsync() כדי ליצור ArResolveAnchorOnRooftopFuture.

בודקים את מצב העוגן על הגג באמצעות ArResolveAnchorOnRooftopFuture_getResultRooftopAnchorState().

כדי לתקן את העוגן שטופל, משתמשים ב-ArResolveAnchorOnRooftopFuture_acquireResultAnchor().

float eus_quaternion_4[4] = {qx, qy, qz, qw};
void* context = NULL;
ArResolveAnchorOnRooftopCallback callback = NULL;
ArResolveAnchorOnRooftopFuture* future = NULL;
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArStatus status = ArEarth_resolveAnchorOnRooftopAsync(
        ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude_above_rooftop, eus_quaternion_4,
        context, callback, &future);
  }
}

בדיקת מצב העתיד

לעתיד יהיה ArFutureState משויך. מידע נוסף זמין בטבלה שלמעלה.

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

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

switch (rooftop_anchor_state) {
  case AR_ROOFTOP_ANCHOR_STATE_SUCCESS:
    // A resolving task for this anchor has been successfully resolved.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the
    // Geospatial API.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/c/group/ar-anchor#:~:text=from%20this%20error.-,AR_ROOFTOP_ANCHOR_STATE_ERROR_NOT_AUTHORIZED,-The%20authorization%20provided
    // for troubleshooting steps.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_INTERNAL:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}

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