מדריך למפתחים למיקומים מיידיים ב-Android NDK

מידע נוסף על שימוש ב-Instant Placement API באפליקציות שלכם.

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

חשוב לוודא שאתם מבינים את המושגים הבסיסיים של AR ואיך להגדיר סשן ARCore לפני שממשיכים.

הגדרת סשן חדש באמצעות מיקום מיידי

בסשן ARCore חדש, מפעילים את מצב מיקום מיידי.

// Create a session config.
ArConfig* ar_config = NULL;
ArConfig_create(ar_session, &ar_config);

// Enable Instant Placement mode.
ArConfig_setInstantPlacementMode(ar_session, ar_config,
                                 AR_INSTANT_PLACEMENT_MODE_LOCAL_Y_UP);
CHECK(ArSession_configure(ar_session, ar_config) == AR_SUCCESS);

// Release config resources.
ArConfig_destroy(ar_config);

הצבת אובייקט

בסשן ARCore חדש, צריך לבצע בדיקת היט של מיקום מיידי באמצעות ArFrame_hitTestInstantPlacement אחר כך יוצרים ArAnchor חדש באמצעות ArInstantPlacementPoint תנוחה מהשדה ARTrackable של תוצאת ההיט.

ArFrame* ar_frame = NULL;
if (ArSession_update(ar_session, ar_frame) != AR_SUCCESS) {
  // Get the latest frame.
  LOGE("ArSession_update error");
  return;
}

// Place an object on tap.
// Use the estimated distance from the user's device to the closest
// available surface, based on expected user interaction and behavior.
float approximate_distance_meters = 2.0f;

ArHitResultList* hit_result_list = NULL;
ArHitResultList_create(ar_session, &hit_result_list);
CHECK(hit_result_list);

// Returns a single result if the hit test was successful.
ArFrame_hitTestInstantPlacement(ar_session, ar_frame, x, y,
                                approximate_distance_meters, hit_result_list);

int32_t hit_result_list_size = 0;
ArHitResultList_getSize(ar_session, hit_result_list, &hit_result_list_size);
if (hit_result_list_size > 0) {
  ArHitResult* ar_hit_result = NULL;
  ArHitResult_create(ar_session, &ar_hit_result);
  CHECK(ar_hit_result);
  ArHitResultList_getItem(ar_session, hit_result_list, 0, ar_hit_result);
  if (ar_hit_result == NULL) {
    LOGE("ArHitResultList_getItem error");
    return;
  }

  ArTrackable* ar_trackable = NULL;
  ArHitResult_acquireTrackable(ar_session, ar_hit_result, &ar_trackable);
  if (ar_trackable == NULL) {
    LOGE("ArHitResultList_acquireTrackable error");
    return;
  }
  ArTrackableType ar_trackable_type = AR_TRACKABLE_NOT_VALID;
  ArTrackable_getType(ar_session, ar_trackable, &ar_trackable_type);

  if (ar_trackable_type == AR_TRACKABLE_INSTANT_PLACEMENT_POINT) {
    ArInstantPlacementPoint* point = (ArInstantPlacementPoint*)ar_trackable;

    // Gets the pose of the Instant Placement point.
    ArPose* ar_pose = NULL;
    ArPose_create(ar_session, NULL, &ar_pose);
    CHECK(ar_pose);
    ArInstantPlacementPoint_getPose(ar_session, point, ar_pose);

    // Attaches an anchor to the Instant Placement point.
    ArAnchor* anchor = NULL;
    ArStatus status = ArTrackable_acquireNewAnchor(ar_session, ar_trackable,
                                                   ar_pose, &anchor);
    ArPose_destroy(ar_pose);
    // Render content at the anchor.
    // ...
  }

  ArTrackable_release(ar_trackable);
}

יש תמיכה בתכונה 'מיקום מיידי' מעקב אחר שטח המסך עם מרחק משוער, מעבר אוטומטי למעקב מלא ברגע שנקודת המיקום המיידי מוטמעת בעולם האמיתי. מאחזרים את התנוחה הנוכחית באמצעות ArInstantPlacementPoint_getPose() קבלת שיטת המעקב הנוכחית באמצעות ArInstantPlacementPoint_getTrackingMethod()

למרות ש-ARCore יכול לבצע בדיקות היטים של מיקומי מודעות מיידיים בפלטפורמות של כל כיוון, תוצאות החיפוש תמיד יחזירו תנוחה עם Y+, כיוון הכובד. בפלטפורמות אופקיות, מבחני ההיטים מוחזרים בצורה מדויקת את מיקומי המודעות שלכם מהר יותר.

מעקב אחר השיטה למעקב אחר נקודות של מיקומי מודעות ללא התקנה

אם ב-ARCore יש תנוחת תלת-ממד מדויקת בשביל ArInstantPlacementPoint שהוחזר על-ידי ArFrame_hitTestInstantPlacement, היא מתחילה בשיטת מעקב AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. אחרת, הוא יתחיל עם שיטת המעקב AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE ומעבר אל AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING כשל-ARCore יש תנוחת תלת-ממד מדויקת. ברגע ששיטת המעקב AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, הוא לא יבוטל אל AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE.

מעבר חלק יותר בין שיטות המעקב

כששיטת המעקב משתנה מ- AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE במסגרת אחת אל AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING בפריים הבא, התנוחה תקפוץ מהמיקום הראשוני שלה סיפק מרחק משוער למיקום חדש, במרחק מדויק. הזה שינוי מיידי בתנוחה משנה את הגודל לכאורה של כל אובייקט מעוגנות ל-ArInstantPositionPoint. כלומר, פתאום אובייקט התמונה גדולה או קטנה יותר מכפי שהיא הייתה במסגרת הקודמת.

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

  1. מעקב אחר התנוחה ושיטת המעקב של ArInstantPlacementPoint בכל מסגרת.
  2. להמתין עד ששיטת המעקב תשתנה ל- AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING
  3. אתם יכולים להשתמש בתנוחה מהפריים הקודם ובתנוחה של הפריים הנוכחי כדי לקבוע את המרחק של העצם למכשיר בשתי המסגרות.
  4. חשבו את השינוי לכאורה בקנה המידה עקב השינוי במרחק מצלמה.
  5. משנים את קנה המידה של האובייקט כדי לנטרל את השינוי הנתפס בקנה מידה כך שלא יהיה ניתן לשנות את גודל האובייקט.
  6. אפשר גם לשנות בצורה חלקה את קנה המידה של האובייקט בחזרה למקור שלו. במספר מסגרות.
class WrappedInstantPlacement {
  ArInstantPlacementPoint* point;
  ArInstantPlacementPointTrackingMethod previous_tracking_method;
  float previous_distance_to_camera;
  float scale_factor = 1.0f;

 public:
  WrappedInstantPlacement(ArInstantPlacementPoint* point,
                          TrackingMethod previous_tracking_method,
                          float previous_distance_to_camera) {
    this.point = point;
    this.previous_tracking_method = previous_tracking_method;
    this.previous_distance_to_camera = previous_distance_to_camera;
  }
};

std::vector<WrappedInstantPlacement> wrapped_points_;

אחרי שיוצרים את הנקודה של מיקום המודעה המיידי, משנים את OnTouched() כך שירוכזו אותה.

if (ar_trackable_type == AR_TRACKABLE_INSTANT_PLACEMENT_POINT) {
  ArInstantPlacementPoint* point = (ArInstantPlacementPoint*)ar_trackable;
  ArInstantPlacementPointTrackingMethod tracking_method;
  ArInstantPlacementPoint_getTrackingMethod(ar_session, point,
                                            &tracking_method);
  ArCamera* ar_camera = nullptr;
  ArFrame_acquireCamera(ar_session, ar_frame, &ar_camera);
  CHECK(ar_camera);
  wrapped_points_.push_back(WrappedInstantPlacement(
      point, tracking_method, Distance(point, ar_camera)));
}

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

void OnUpdate() {
  for (auto& wrapped_point : wrapped_points_) {
    ArInstantPlacementPoint* point = wrapped_point.point;

    ArTrackingState tracking_state = AR_TRACKING_STATE_STOPPED;
    ArTrackable_getTrackingState(ar_session, (ArTrackable)point,
                                 &tracking_state);

    if (tracking_state == AR_TRACKING_STATE_STOPPED) {
      wrapped_points_.remove(wrapped_point);
      continue;
    }
    if (tracking_state == AR_TRACKING_STATE_PAUSED) {
      continue;
    }

    ArInstantPlacementPointTrackingMethod tracking_method;
    ArInstantPlacementPoint_getTrackingMethod(ar_session, point,
                                              &tracking_method);
    ArCamera* ar_camera = nullptr;
    ArFrame_acquireCamera(ar_session, ar_frame, &ar_camera);
    CHECK(ar_camera);
    const float distance_to_camera = Distance(point, ar_camera);
    if (tracking_method ==
        AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE) {
      // Continue to use the estimated depth and pose. Record the distance to
      // the camera for use in the next frame if the transition to full
      // tracking happens.
      wrapped_point.previous_distance_to_camera = distance_to_camera;
    } else if (
        tracking_method ==
            AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING &&
        wrapped_point.previous_tracking_method ==
            AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE) {
      // Change from the estimated pose to the accurate pose. Adjust the
      // object scale to counteract the apparent change due to pose jump.
      wrapped_point.scale_factor =
          distance_to_camera / wrapped_point.previous_distance_to_camera;
      // Apply the scale factor to the model.
      // ...
      previous_tracking_method =
          AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING;
    }
  }
}

שיקולי ביצועים

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

כאשר המיקום המיידי מושבת, משתמשים ArFrame_hitTest במקום ArFrame_hitTestInstantPlacement

ArConfig* ar_config = NULL;
ArConfig_create(ar_session, &ar_config);
// Disable Instant Placement.
ArConfig_setInstantPlacementMode(ar_session, ar_config,
                                 AR_INSTANT_PLACEMENT_MODE_DISABLED);
CHECK(ArSession_configure(ar_session, ar_config) == AR_SUCCESS);
ArConfig_destroy(ar_config);