Entwicklerleitfaden für Instant Placements für Android NDK

Instant Placement API in Ihren eigenen Apps verwenden

Voraussetzungen

Machen Sie sich mit den grundlegenden AR-Konzepten und zur Konfiguration einer ARCore-Sitzung vertraut, bevor Sie fortfahren.

Neue Sitzung mit Instant Placement konfigurieren

Aktivieren Sie in einer neuen ARCore-Sitzung den Instant-Placement-Modus.

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

Objekt platzieren

Führe in einer neuen ARCore-Sitzung mit ArFrame_hitTestInstantPlacement einen Treffertest für das Instant-Placement durch. Erstellen Sie dann ein neues ArAnchor mit der ArInstantPlacementPoint-Pose aus dem ARTrackable des Trefferergebnisses.

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 unterstützt das Tracking des Bildschirmbereichs mit ungefährer Entfernung. Sobald der Instant Placement-Punkt in der realen Welt verankert ist, wird automatisch zum vollständigen Tracking gewechselt. Rufen Sie die aktuelle Pose mit ArInstantPlacementPoint_getPose() ab. Rufen Sie die aktuelle Tracking-Methode mit ArInstantPlacementPoint_getTrackingMethod() ab.

ARCore kann Instant-Placement-Treffertests für Oberflächen mit beliebiger Ausrichtung durchführen, in den Trefferergebnissen wird jedoch immer eine Pose mit einem „+Y“ nach oben und gegen die Schwerkraft zurückgegeben. Auf horizontalen Oberflächen geben Treffertests genaue Positionen viel schneller zurück.

Punkt-Tracking-Methode für Instant Placements überwachen

Wenn ARCore eine genaue 3D-Pose für das von ArFrame_hitTestInstantPlacement zurückgegebene ArInstantPlacementPoint hat, beginnt es mit der Tracking-Methode AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING. Andernfalls beginnt es mit der Tracking-Methode AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE und wechselt zu AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING, sobald ARCore eine genaue 3D-Pose hat. Wenn die Tracking-Methode AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING ist, wird sie nicht wieder auf AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE zurückgesetzt.

Den Übergang zur Tracking-Methode ausgleichen

Wenn die Tracking-Methode in einem Frame von AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE zu AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING im nächsten Frame wechselt, springt die Pose von ihrer ursprünglichen Position anhand der angegebenen ungefähren Entfernung zu einem neuen Standort aus einer genauen Entfernung. Diese sofortige Änderung der Pose ändert den sichtbaren Maßstab aller Objekte, die am ArInstantPlacementPoint verankert sind. Das heißt, ein Objekt erscheint plötzlich größer oder kleiner als im vorherigen Frame.

Gehen Sie so vor, um den visuellen Sprung aufgrund der plötzlichen Änderung der Größe des Objekts zu vermeiden:

  1. Behalten Sie die Position und die Nachverfolgungsmethode von ArInstantPlacementPoint in jedem Frame im Blick.
  2. Warten Sie, bis die Tracking-Methode zu AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING geändert wurde.
  3. Verwenden Sie die Pose aus dem vorherigen Frame und die Pose im aktuellen Frame, um den Abstand des Objekts zum Gerät in beiden Frames zu bestimmen.
  4. Berechnen Sie die scheinbare Größenänderung aufgrund der Änderung des Abstands zur Kamera.
  5. Passen Sie die Größe des Objekts an, um der wahrgenommenen Skalierungsänderung entgegenzuwirken, sodass sich die Größe des Objekts nicht ändert.
  6. Optional können Sie die Skalierung des Objekts über mehrere Frames hinweg wieder auf den ursprünglichen Wert zurücksetzen.
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_;

Nachdem Sie den Instant Placement-Punkt erstellt haben, ändern Sie OnTouched(), um ihn zu umschließen.

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

Wenn die Tracking-Methode des Sofortplatzierungspunkts von AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_SCREENSPACE_WITH_APPROXIMATE_DISTANCE zu AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING wechselt, verwenden Sie die gespeicherte Entfernung, um der scheinbaren Skalierungsänderung entgegenzuwirken.

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

Hinweise zur Leistung

Wenn Instant Placement aktiviert ist, verbraucht ARCore zusätzliche CPU-Zyklen. Ist die Leistung beeinträchtigt, können Sie die Instant-Platzierung deaktivieren, nachdem der Nutzer sein Objekt erfolgreich platziert hat und die Tracking-Methode für alle Instant Placement-Punkte zu AR_INSTANT_PLACEMENT_POINT_TRACKING_METHOD_FULL_TRACKING geändert wurde.

Wenn Instant Placement deaktiviert ist, verwenden Sie ArFrame_hitTest anstelle von 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);