Hướng dẫn dành cho nhà phát triển về Vị trí tức thì dành cho Android NDK

Tìm hiểu cách sử dụng API Vị trí tức thì trong ứng dụng của chính bạn.

Điều kiện tiên quyết

Đảm bảo rằng bạn hiểu rõ các khái niệm cơ bản về AR và cách định cấu hình phiên ARCore trước khi tiếp tục.

Định cấu hình một phiên mới với Vị trí tức thì

Trong phiên ARCore mới, hãy bật chế độ Vị trí tức thì.

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

Đặt một đối tượng

Trong phiên ARCore mới, hãy thực hiện kiểm tra lượt truy cập Vị trí tức thì với ArFrame_hitTestInstantPlacement. Sau đó, tạo một ArAnchor mới bằng cách sử dụng Tư thế ArInstantPlacementPoint từ ARTrackable của kết quả lượt truy cập.

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

Hỗ trợ Vị trí tức thì theo dõi không gian màn hình với khoảng cách gần đúng, tự động chuyển sang theo dõi đầy đủ khi Điểm Vị trí tức thì được gắn liền với thế giới thực. Truy xuất tư thế hiện tại bằng ArInstantPlacementPoint_getPose(). Tải phương pháp theo dõi hiện tại bằng ArInstantPlacementPoint_getTrackingMethod().

Mặc dù ARCore có thể thực hiện kiểm tra nhấn Vị trí tức thì trên các nền tảng của bất kỳ hướng, kết quả đánh sẽ luôn trả về tư thế với +Y lên, ngược với hướng trọng lực. Trên các bề mặt nằm ngang, các bài kiểm thử va chạm trả về kết quả chính xác vị trí nhanh hơn nhiều.

Theo dõi phương pháp theo dõi điểm Vị trí tức thì

Nếu ARCore có tư thế 3D chính xác cho ArInstantPlacementPoint được trả về bởi ArFrame_hitTestInstantPlacement, bắt đầu bằng phương pháp theo dõi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. Nếu không, chiến dịch sẽ bắt đầu bằng phương pháp theo dõi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE và chuyển đổi sang AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING khi ARCore có tư thế 3D chính xác. Khi phương pháp theo dõi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, sự kiện này sẽ không khôi phục về trạng thái ban đầu đến AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE

Dễ dàng chuyển đổi phương pháp theo dõi

Khi phương pháp theo dõi thay đổi từ AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE trong một khung hình đến AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING trong khung hình tiếp theo, tư thế đó sẽ nhảy từ vị trí ban đầu dựa trên đã cung cấp khoảng cách gần đúng đến một vị trí mới với khoảng cách chính xác. Chiến dịch này sự thay đổi tức thời về tư thế làm thay đổi tỷ lệ biểu kiến của bất kỳ vật thể nào được neo vào Ar InstantLocationsPoint. Điều đó nghĩa là một đối tượng đột nhiên xuất hiện lớn hơn hoặc nhỏ hơn so với khung trước đó.

Hãy làm theo các bước sau để tránh hiện tượng nhảy hình ảnh do sự thay đổi đột ngột về độ rõ ràng tỷ lệ đối tượng:

  1. Theo dõi tư thế và phương pháp theo dõi của ArInstantPlacementPoint trong từng khung hình.
  2. Chờ phương pháp theo dõi đổi thành AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Sử dụng tư thế từ khung hình trước và tư thế trong khung hình hiện tại để xác định khoảng cách của đối tượng đến thiết bị trong cả hai khung.
  4. Tính sự thay đổi biểu kiến về tỷ lệ do sự thay đổi về khoảng cách từ máy ảnh.
  5. Điều chỉnh tỷ lệ của đối tượng để chống lại sự thay đổi cảm nhận về quy mô, sao cho đối tượng không thay đổi kích thước về mặt trực quan.
  6. Không bắt buộc: Điều chỉnh tỷ lệ của đối tượng về trạng thái ban đầu (không bắt buộc) trên một số khung hình.
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_;

Sau khi tạo điểm Vị trí tức thì, hãy sửa đổi OnTouched() để gói điểm đó.

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

Khi phương pháp theo dõi của điểm Vị trí tức thì chuyển từ AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE đến AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, hãy sử dụng khoảng cách để chống lại sự thay đổi tỷ lệ biểu kiến.

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

Xem xét hiệu suất

Khi bật Vị trí tức thì, ARCore sẽ sử dụng thêm chu kỳ CPU. Nếu bạn quan tâm đến hiệu suất, hãy xem xét việc tắt Vị trí tức thì sau khi người dùng đã đặt thành công đối tượng và phương pháp theo dõi của tất cả Điểm vị trí đã thay đổi thành AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

Khi Vị trí tức thì bị tắt, hãy sử dụng ArFrame_hitTest thay vì 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);