Guide du développeur sur l'emplacement instantané pour le NDK Android

Découvrez comment utiliser l'API Instant Placement dans vos propres applications.

Conditions préalables

Assurez-vous de bien comprendre les concepts fondamentaux de la RA et de configurer une session ARCore avant de continuer.

Configurer une nouvelle session avec Instant Placement

Dans une nouvelle session ARCore, activez le mode "Emplacement instantané".

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

Placer un objet

Dans une nouvelle session ARCore, effectuez un test de positionnement instantané avec ArFrame_hitTestInstantPlacement. Créez ensuite un ArAnchor à l'aide de la ArInstantPlacementPoint à partir du ARTrackable du résultat de l'appel.

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 est compatible avec le suivi de l'espace à l'écran avec une distance approximative, et passe automatiquement au suivi complet une fois que le point d'emplacement instantané est ancré dans le monde réel. Récupérez la pose actuelle avec ArInstantPlacementPoint_getPose(). Obtenez la méthode de suivi actuelle avec ArInstantPlacementPoint_getTrackingMethod().

Bien qu'ARCore puisse effectuer des tests de positionnement instantanés sur des surfaces de n'importe quelle orientation, les résultats de positionnement renvoient toujours une posture avec +Y vers le haut, contre la direction de la gravité. Sur les surfaces horizontales, les tests de positionnement renvoient des positions précises beaucoup plus rapidement.

Surveiller la méthode de suivi des points d'emplacement instantané

Si ARCore présente une position 3D précise pour l'élément ArInstantPlacementPoint renvoyé par ArFrame_hitTestInstantPlacement, il commence par la méthode de suivi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. Sinon, il commencera avec la méthode de suivi AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE et passera à AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING une fois qu'ARCore aura trouvé une position 3D précise. Une fois que la méthode de suivi est définie sur AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, la valeur AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE n'est pas rétablie.

Faciliter la transition des méthodes de suivi

Lorsque la méthode de suivi passe de AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE dans une image à AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING dans l'image suivante, la posture saute de son emplacement initial en fonction de la distance approximative fournie jusqu'à un nouveau lieu et à une distance précise. Ce changement instantané de position modifie l'échelle apparente de tous les objets ancrés à l'ArInstantPlacementPoint. En d'autres termes, un objet apparaît soudainement plus grand ou plus petit que dans l'image précédente.

Suivez ces étapes pour éviter le saut visuel en raison du changement soudain de l'échelle des objets:

  1. Effectuez le suivi de la méthode de pose et de suivi de ArInstantPlacementPoint dans chaque image.
  2. Attendez que la méthode de suivi passe à AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Utilisez la pose de l'image précédente et celle de l'image actuelle pour déterminer la distance entre l'objet et l'appareil dans les deux images.
  4. Calculez le changement apparent d'échelle dû à la variation de la distance par rapport à la caméra.
  5. Ajustez l'échelle de l'objet pour contrebalancer le changement d'échelle perçu, afin que la taille de l'objet ne semble pas changer visuellement.
  6. Si vous le souhaitez, vous pouvez rétablir l'échelle de l'objet à sa valeur d'origine sur plusieurs images.
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_;

Après avoir créé le point d'emplacement instantané, modifiez OnTouched() pour l'encapsuler.

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

Lorsque la méthode de suivi du point d'emplacement instantané passe de AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE à AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, utilisez la distance enregistrée pour contrebalancer le changement d'échelle apparent.

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

Considérations sur les performances

Lorsque l'emplacement instantané est activé, ARCore consomme des cycles de processeur supplémentaires. Si les performances posent problème, envisagez de désactiver l'emplacement instantané une fois que l'utilisateur a placé son objet et que la méthode de suivi de tous les points d'emplacement instantané est passée à AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

Lorsque l'emplacement instantané est désactivé, utilisez ArFrame_hitTest au lieu de 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);