Panduan developer Penempatan Instan untuk Android NDK

Pelajari cara menggunakan Instant Placement API di aplikasi Anda sendiri.

Prasyarat

Pastikan Anda memahami konsep AR dasar dan cara mengonfigurasi sesi ARCore sebelum melanjutkan.

Mengonfigurasi sesi baru dengan Penempatan Instan

Di sesi ARCore baru, aktifkan mode Penempatan Instan.

// 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);

Menempatkan objek

Dalam sesi ARCore baru, lakukan hit-test Penempatan Instan dengan ArFrame_hitTestInstantPlacement. Kemudian, buat ArAnchor baru menggunakan pose ArInstantPlacementPoint dari ARTrackable hasil hit.

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

Penempatan Instan mendukung pelacakan ruang layar dengan perkiraan jarak, yang secara otomatis beralih ke pelacakan penuh setelah titik Penempatan Instan ditautkan di dunia nyata. Mengambil pose saat ini dengan ArInstantPlacementPoint_getPose(). Mendapatkan metode pelacakan saat ini dengan ArInstantPlacementPoint_getTrackingMethod().

Meskipun ARCore dapat melakukan hit-test Penempatan Instan terhadap permukaan orientasi apa pun, hasil hit akan selalu menampilkan pose dengan +Y ke atas, terhadap arah gravitasi. Pada permukaan horizontal, hit-test menampilkan posisi yang akurat dengan jauh lebih cepat.

Memantau metode pelacakan titik Penempatan Instan

Jika ARCore memiliki pose 3D yang akurat untuk ArInstantPlacementPoint yang ditampilkan oleh ArFrame_hitTestInstantPlacement, ARCore akan dimulai dengan metode pelacakan AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. Jika tidak, ARCore akan dimulai dengan metode pelacakan AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE dan beralih ke AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING setelah ARCore memiliki pose 3D yang akurat. Setelah metode pelacakan AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, metode tersebut tidak akan dikembalikan ke AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE.

memperlancar transisi metode pelacakan

Saat metode pelacakan berubah dari AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE dalam satu frame ke AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING di frame berikutnya, pose akan melompat dari lokasi awalnya berdasarkan perkiraan jarak yang diberikan ke lokasi baru pada jarak yang akurat. Perubahan pose instan ini mengubah skala yang jelas dari setiap objek yang ditambatkan ke ArInstantPlacementPoint. Artinya, sebuah objek tiba-tiba tampak lebih besar atau lebih kecil daripada di {i>frame<i} sebelumnya.

Ikuti langkah-langkah berikut untuk menghindari lompatan visual karena perubahan mendadak pada skala objek yang terlihat:

  1. Lacak pose dan metode pelacakan ArInstantPlacementPoint di setiap frame.
  2. Tunggu hingga metode pelacakan berubah menjadi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Gunakan pose dari frame sebelumnya dan pose dalam frame saat ini untuk menentukan jarak objek ke perangkat di kedua frame.
  4. Hitung perubahan skala yang terlihat karena perubahan jarak dari kamera.
  5. Sesuaikan skala objek untuk melawan perubahan skala yang dirasakan, sehingga objek tidak tampak berubah ukurannya secara visual.
  6. Secara opsional, sesuaikan skala objek kembali ke nilai aslinya dengan lancar melalui beberapa frame.
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_;

Setelah membuat titik Penempatan Instan, ubah OnTouched() untuk menggabungkannya.

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

Saat metode pelacakan titik Penempatan Instan bertransisi dari AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE ke AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, gunakan jarak yang disimpan untuk menangkal perubahan skala yang jelas.

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

Pertimbangan performa

Jika Penempatan Instan diaktifkan, ARCore akan menggunakan siklus CPU tambahan. Jika performa menjadi masalah, pertimbangkan untuk menonaktifkan Penempatan Instan setelah pengguna berhasil menempatkan objek dan metode pelacakan semua titik Penempatan Instan telah berubah menjadi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

Jika Penempatan Instan dinonaktifkan, gunakan ArFrame_hitTest, bukan 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);