Guía para desarrolladores sobre la Posición instantánea en el NDK de Android

Aprende a utilizar la API de Instant Placement. en tus propias apps.

Requisitos previos

Asegúrate de comprender los conceptos fundamentales de RA y cómo configurar una sesión de ARCore antes de continuar.

Configurar una nueva sesión con Posición instantánea

En una nueva sesión de ARCore, habilita el modo de posición instantánea.

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

Coloca un objeto

En una nueva sesión de ARCore, realiza una prueba de posicionamiento de posición instantánea con ArFrame_hitTestInstantPlacement Luego, crea un ArAnchor nuevo con el elemento pose de ArInstantPlacementPoint del ARTrackable del resultado del hit.

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

La ubicación instantánea admite seguimiento del espacio en pantalla con distancia aproximada, cambiar automáticamente al seguimiento completo una vez que el punto de ubicación instantánea se se basa en el mundo real. Recupera la pose actual con ArInstantPlacementPoint_getPose() Obtén el método de seguimiento actual con ArInstantPlacementPoint_getTrackingMethod()

Si bien ARCore puede realizar pruebas de posicionamiento de ubicación instantánea en superficies de cualquier orientación, los resultados de la selección siempre devolverán una pose con +Y hacia arriba, frente al en la dirección de gravedad. En superficies horizontales, las pruebas de posicionamiento muestran posiciones mucho más rápido.

Supervisar el método de seguimiento de puntos de la posición instantánea

Si ARCore tiene una pose en 3D precisa para el ArInstantPlacementPoint que devuelve ArFrame_hitTestInstantPlacement, comienza con el método de seguimiento AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING De lo contrario, comenzará con el método de seguimiento AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE. y hacer la transición a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING una vez que ARCore tenga una postura en 3D precisa. Una vez que el método de seguimiento AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, no se revertirá a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE

Cómo suavizar la transición del método de seguimiento

Cuando el método de seguimiento cambia de AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE en un fotograma a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING en la siguiente imagen, la postura salta desde su ubicación inicial según la proporcionó una distancia aproximada a una ubicación nueva a una distancia precisa. Esta un cambio instantáneo en la pose cambia la escala aparente de los objetos que se anclan a ArInstantColocaPoint. Es decir, un objeto de repente se vea más grande o más pequeño que en el marco anterior.

Sigue estos pasos para evitar el salto visual debido al cambio repentino en la apariencia Escalamiento de objetos:

  1. Haz un seguimiento de la pose y el método de seguimiento de ArInstantPlacementPoint. en cada marco.
  2. Espere hasta que el método de seguimiento cambie a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING
  3. Usa la pose del cuadro anterior y la del marco actual para determinar la distancia del objeto al dispositivo en ambos fotogramas.
  4. Calcula el cambio aparente en la escala debido al cambio en la distancia desde el cámara.
  5. Ajustar la escala del objeto para contrarrestar el cambio percibido en la escala, para que el objeto no parezca cambiar visualmente de tamaño.
  6. De manera opcional, puedes volver a ajustar sin problemas la escala del objeto a su estado original. valor en varios fotogramas.
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_;

Después de crear el punto de posición instantánea, modifica OnTouched() para unirlo.

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

Cuando el método de seguimiento del punto de Posición instantánea hace la transición de AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, usa la distancia para contrarrestar el cambio de escala aparente.

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

Consideraciones de rendimiento

Cuando la posición instantánea está habilitada, ARCore consume ciclos de CPU adicionales. Si el rendimiento es un problema, considera inhabilitar la ubicación instantánea después de que el usuario haya colocado correctamente su objeto y el método de seguimiento de todas las instancias Los puntos de posición cambiaron a AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING

Si la Ubicación instantánea está inhabilitada, usa ArFrame_hitTest en lugar 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);