Guida per gli sviluppatori del posizionamento istantaneo per Android NDK

Scopri come utilizzare l'API Instant Placement nelle tue app.

Prerequisiti

Assicurati di aver compreso i concetti fondamentali di AR e di configurare una sessione ARCore prima di procedere.

Configurare una nuova sessione con il posizionamento istantaneo

In una nuova sessione ARCore, abilita la modalità Posizionamento istantaneo.

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

Posizionare un oggetto

In una nuova sessione ARCore, esegui un hit test di posizionamento istantaneo con ArFrame_hitTestInstantPlacement. Quindi crea una nuova ArAnchor usando la posa ArInstantPlacementPoint del risultato dell'hit 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);
}

Il Posizionamento istantaneo supporta il monitoraggio dello spazio sullo schermo con una distanza approssimativa, passando automaticamente al tracciamento completo una volta che il punto di Posizionamento istantaneo è ancorato nel mondo reale. Recupera la posizione attuale con ArInstantPlacementPoint_getPose(). Ottieni il metodo di monitoraggio attuale con ArInstantPlacementPoint_getTrackingMethod().

Anche se ARCore può eseguire hit test di posizionamento istantaneo su superfici con qualsiasi orientamento, i risultati degli hit restituiranno sempre una posa con +Y in alto, in contrasto con la direzione di gravità. Sulle superfici orizzontali, gli hit test restituiscono posizioni precise molto più velocemente.

Monitorare il metodo di monitoraggio dei punti del Posizionamento istantaneo

Se ARCore ha una posa 3D accurata per l'elemento ArInstantPlacementPoint restituito da ArFrame_hitTestInstantPlacement, inizia con il metodo di monitoraggio AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. In caso contrario, inizierà con il metodo di monitoraggio AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE e passerà a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING una volta che ARCore avrà una posa 3D accurata. Una volta che il metodo di monitoraggio è AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, non verrà ripristinato su AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE.

Semplifica la transizione del metodo di monitoraggio

Quando il metodo di monitoraggio passa da AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE in un frame a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING nel frame successivo, la posa salta dalla posizione iniziale in base alla distanza approssimativa fornita a una nuova posizione a una distanza precisa. Questo cambiamento istantaneo della posa cambia la scala apparente di tutti gli oggetti ancorati ad Ar Instant PlacementPoint. Ciò significa che un oggetto appare improvvisamente più grande o più piccolo rispetto al frame precedente.

Segui questi passaggi per evitare il salto visivo dovuto al cambiamento improvviso nella scala dell'oggetto apparente:

  1. Monitora la posa e il metodo di monitoraggio di ArInstantPlacementPoint in ogni frame.
  2. Attendi che il metodo di monitoraggio passi a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.
  3. Utilizza la posa del frame precedente e quella nell'attuale fotogramma per determinare la distanza dell'oggetto dal dispositivo in entrambi i fotogrammi.
  4. Calcola il cambiamento apparente di scala dovuto alla variazione di distanza dalla fotocamera.
  5. Regola la scala dell'oggetto per contrastare il cambiamento percepito di scala, in modo che l'oggetto non sembri cambiare visivamente di dimensione.
  6. Facoltativamente, ripristina il valore originale della scala dell'oggetto su più frame.
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_;

Dopo aver creato il punto di Posizionamento istantaneo, modifica OnTouched() per aggregarlo.

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

Quando il metodo di monitoraggio del punto di Posizionamento istantaneo passa da AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, utilizza la distanza salvata per contrastare l'apparente variazione della scala.

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

Considerazioni sul rendimento

Quando il posizionamento istantaneo è abilitato, ARCore consuma cicli della CPU aggiuntivi. Se il rendimento è un problema, valuta la possibilità di disattivare il Posizionamento istantaneo dopo che l'utente ha posizionato correttamente l'oggetto e il metodo di monitoraggio di tutti i punti del Posizionamento istantaneo è cambiato in AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING.

Quando il posizionamento istantaneo è disattivato, utilizza ArFrame_hitTest anziché 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);