Panduan developer Penempatan Instan untuk Android NDK

Pelajari cara menggunakan Instant Placement API di aplikasi Anda sendiri.

Prasyarat

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

Mengonfigurasi sesi baru dengan Penempatan Instan

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

Tempatkan objek

Dalam sesi ARCore baru, lakukan hit-test Penempatan Instan dengan ArFrame_hitTestInstantPlacement Lalu, 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);
}

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

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

Memantau metode pelacakan titik Penempatan Instan

Jika ARCore memiliki pose 3D yang akurat untuk ArInstantPlacementPoint yang ditampilkan oleh ArFrame_hitTestInstantPlacement, dimulai dengan metode pelacakan AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING Jika tidak, konversi akan dimulai dengan metode pelacakan AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE dan bertransisi 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, item ini tidak akan dikembalikan dapat AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE.

Memuluskan transisi metode pelacakan

Ketika 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 {i>frame<i} berikutnya, pose melompat dari lokasi awal berdasarkan memberikan perkiraan jarak ke lokasi baru pada jarak yang akurat. Ini perubahan instan dalam pose mengubah skala jelas dari setiap objek yang ditambatkan ke ArInstant PlacementPoint. Artinya, suatu objek tiba-tiba tampak lebih besar atau lebih kecil daripada {i>frame<i} sebelumnya.

Ikuti langkah-langkah berikut untuk menghindari lompatan visual karena perubahan mendadak yang terlihat {i>object scale<i} (skala objek):

  1. Lacak metode pose dan pelacakan ArInstantPlacementPoint di setiap {i>frame<i}.
  2. Tunggu hingga metode pelacakan berubah menjadi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Gunakan pose dari {i>frame<i} sebelumnya dan pose dalam {i>frame<i} saat ini untuk menentukan jarak objek ke perangkat di kedua {i>frame<i}.
  4. Hitung perubahan yang jelas dalam skala karena perubahan jarak dari kamera.
  5. Sesuaikan skala objek untuk melawan perubahan yang dirasakan dalam skala, sehingga objek tidak tampak berubah secara visual.
  6. Jika perlu, sesuaikan skala objek kembali ke ukuran aslinya dengan halus selama beberapa {i>frame<i}.
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)));
}

Ketika 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 disimpan untuk melawan 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 Instant Placement diaktifkan, ARCore menggunakan siklus CPU tambahan. Jika performa menjadi perhatian pengguna, pertimbangkan untuk menonaktifkan Penempatan Instan setelah pengguna telah berhasil menempatkan objek mereka dan metode pelacakan semua Titik penempatan telah berubah menjadi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

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