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 riêng bạn.

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

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

Định cấu hình phiên mới bằng 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 thử nghiệm lần truy cập Vị trí tức thì bằng 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);
}

Vị trí tức thì hỗ trợ 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 đủ sau khi điểm Vị trí tức thì được cố định trong thế giới thực. Truy xuất tư thế hiện tại bằng ArInstantPlacementPoint_getPose(). Nhận phương thức theo dõi hiện tại bằng ArInstantPlacementPoint_getTrackingMethod().

Mặc dù ARCore có thể thực hiện thử nghiệm lượt truy cập Vị trí tức thì trên các bề mặt thuộc bất kỳ hướng nào, nhưng kết quả lượt truy cập sẽ luôn trả về một tư thế có + Y hướng lên, ngược lại với hướng trọng lực. Trên các nền tảng ngang, phép kiểm thử lượt truy cập trả về vị trí chính xác 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 do ArFrame_hitTestInstantPlacement trả về, thì ARCore sẽ bắt đầu bằng phương thức theo dõi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. Nếu không, quá trình này sẽ bắt đầu bằng phương thức theo dõi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE và chuyển sang AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING sau khi ARCore có tư thế 3D chính xác. Khi là phương thức theo dõi là AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, phương thức đó sẽ không hoàn nguyên về AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE.

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

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 thành 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 khoảng cách gần đúng đã cung cấp đến một vị trí mới với khoảng cách chính xác. Sự thay đổi tức thì về tư thế này sẽ thay đổi tỷ lệ rõ ràng của mọi đối tượng được neo vào ArInstantPlacementPoint. Điều này 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 đối tượng trong khung trước.

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

  1. Theo dõi tư thế và phương pháp theo dõi của ArInstantPlacementPoint trong mỗi khung hình.
  2. Chờ phương thức theo dõi thay đổi thành AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Sử dụng tư thế từ khung trước và tư thế trong khung 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 toán sự thay đổi rõ ràng về tỷ lệ do 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 về tỷ lệ cảm nhận được để đối tượng không thay đổi về kích thước.
  6. Bạn có thể tuỳ ý điều chỉnh tỷ lệ của đối tượng về giá trị ban đầu trên một vài khung hình (không bắt buộc).
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 này.

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 đổi từ AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE sang AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, hãy sử dụng khoảng cách đã lưu để chống lại sự thay đổi rõ ràng về tỷ lệ.

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ẽ tiêu thụ thêm chu kỳ CPU. Nếu bạn lo ngại về hiệu suất, hãy cân nhắc tắt tính năng Vị trí tức thì sau khi người dùng đặt thành công đối tượng của họ và phương pháp theo dõi của tất cả các điểm Vị trí tức thì đã thay đổi thành AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

Khi tính năng Vị trí tức thì đang 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);