راهنمای برنامه‌نویس Instant Placement برای Android NDK

با نحوه استفاده از Instant Placement API در برنامه های خود آشنا شوید.

پیش نیازها

قبل از ادامه، مطمئن شوید که مفاهیم اساسی AR و نحوه پیکربندی یک جلسه ARCore را درک کرده اید.

یک جلسه جدید را با Instant Placement پیکربندی کنید

در یک جلسه ARCore جدید، حالت Instant Placement را فعال کنید.

// 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 جدید، تست ضربه‌ای Instant Placement را با 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);
}

Instant Placement از ردیابی فضای صفحه با فاصله تقریبی پشتیبانی می‌کند، پس از اینکه نقطه قرار دادن فوری در دنیای واقعی لنگر انداخته شد، به طور خودکار به ردیابی کامل تغییر می‌کند. حالت فعلی را با ArInstantPlacementPoint_getPose() بازیابی کنید. روش ردیابی فعلی را با ArInstantPlacementPoint_getTrackingMethod() دریافت کنید.

اگرچه ARCore می‌تواند تست‌های ضربه‌گیری Instant Placement را در برابر سطوح با هر جهتی انجام دهد، نتایج ضربه همیشه یک حالت با +Y به بالا، برخلاف جهت گرانش، برمی‌گرداند. در سطوح افقی، تست های ضربه ای موقعیت های دقیق را بسیار سریعتر برمی گرداند.

روش ردیابی نقطه قرار دادن فوری را نظارت کنید

اگر ARCore یک حالت سه بعدی دقیق برای ArInstantPlacementPoint ارائه شده توسط ArFrame_hitTestInstantPlacement داشته باشد، با روش ردیابی AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING شروع می شود. در غیر این صورت، با روش ردیابی AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE شروع می شود و به محض اینکه ARCDore یک Po33 دقیق داشته باشد به AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING منتقل می شود. هنگامی که روش ردیابی 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 در فریم بعدی تغییر می‌کند، برنامه بر اساس فاصله زمانی دقیق به موقعیت مکانی جدید، یک پرش دقیق از موقعیت مکانی جدید را ارائه می‌کند. این تغییر آنی در حالت، مقیاس ظاهری هر شیئی را که به ArInstantPlacementPoint متصل شده اند، تغییر می دهد. یعنی یک شی به طور ناگهانی بزرگتر یا کوچکتر از آنچه در فریم قبلی بود به نظر می رسد.

برای جلوگیری از پرش بصری به دلیل تغییر ناگهانی در مقیاس ظاهری شی، این مراحل را دنبال کنید:

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

پس از ایجاد نقطه Instant Placement، OnTouched() را برای wrap تغییر دهید.

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

ملاحظات عملکرد

وقتی Instant Placement فعال است، ARCore چرخه های CPU اضافی را مصرف می کند. اگر عملکرد نگران کننده است، پس از اینکه کاربر با موفقیت شی خود را قرار داد و روش ردیابی همه نقاط Instant Placement به AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING تغییر کرد، Instant Placement را غیرفعال کنید.

وقتی Instant Placement غیرفعال است، از 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);