Làm việc với ARCore cho Jetpack XR

ARCore cho Jetpack XR cho phép các ứng dụng hoạt động với các khái niệm cơ bản về thực tế tăng cường (AR), sử dụng các nguyên mẫu nhận biết cảnh cấp thấp và tính năng theo dõi chuyển động. Sử dụng ARCore cho Jetpack XR khi xây dựng trải nghiệm AR và bạn cần sử dụng dữ liệu mặt phẳng hoặc nội dung neo vào một vị trí cố định trong không gian.

Tìm hiểu về vòng đời của Phiên

Bạn phải truy cập vào tất cả đối tượng do ARCore theo dõi cho Jetpack XR thông qua một Phiên. Tương tự như vòng đời của Hoạt động, các đối tượng Phiên cũng có một vòng đời phải được duy trì theo cách ứng dụng của bạn sử dụng các tính năng của đối tượng Phiên. Nếu ứng dụng của bạn chứa một hoạt động hỗ trợ XR, hãy cân nhắc việc xử lý vòng đời của Phiên bằng thành phần nhận biết vòng đời.

Tạo phiên

Bạn phải tạo một Phiên thì mới có thể sử dụng phiên đó. Để tạo một phiên, người dùng phải cấp quyền android.permission.SCENE_UNDERSTANDING cho ứng dụng của bạn.

Cách tạo phiên:

when (val result = Session.create(owner)) {
  is SessionCreateSuccess -> {
    session = result.session
  }
  is SessionCreatePermissionsNotGranted -> {
   // Request android.permission.SCENE_UNDERSTANDING.
  }
}

Hãy xem SessionCreateResult để biết lý do khiến không thể tạo Phiên.

Tiếp tục phiên

Bạn nên tiếp tục phiên khi ứng dụng của bạn đã sẵn sàng xử lý các thay đổi về trạng thái từ ARCore cho Jetpack XR. Trong nhiều trường hợp, việc này được thực hiện trong lệnh gọi lại onResume() của Hoạt động, nhưng ứng dụng của bạn có thể muốn trì hoãn quá trình xử lý cho đến khi người dùng tương tác.

Đoạn mã sau đây cho thấy ví dụ về cách tiếp tục một phiên.

when (val result = session.resume()) {
  is SessionResumeSuccess -> {
    // Session has been created successfully.
    // Attach any successful handlers here.
  }
  is SessionResumePermissionsNotGranted -> {
    // Request android.permission.SCENE_UNDERSTANDING.
}

Hãy xem SessionResumeResult để biết lý do khiến Phiên không thể tiếp tục.

Tạm dừng một phiên

Khi hoạt động của bạn chuyển sang chế độ nền, hãy tạm dừng Phiên bằng cách sử dụng Session.pause(). Thao tác tạm dừng phiên sẽ tạm thời dừng quá trình theo dõi cho đến khi phiên được tiếp tục, duy trì trạng thái của hệ thống nhận thức.

Huỷ phiên

Để loại bỏ vĩnh viễn một phiên, hãy sử dụng Session.destroy(). Thao tác này sẽ giải phóng các tài nguyên đang được phiên sử dụng và huỷ bỏ tất cả trạng thái phiên.

Truy xuất trạng thái của các mặt phẳng được nhận biết

ARCore cho Jetpack XR cung cấp trạng thái của các mặt phẳng thông qua một StateFlow phát ra trạng thái của các mặt phẳng. Việc đăng ký các chuyến bay trong một phiên sẽ thông báo cho ứng dụng của bạn khi các chuyến bay được thêm, cập nhật hoặc xoá.

Plane.subscribe(session).collect { planes ->
 // Planes have changed; update plane rendering
}

Một mặt phẳng có các thuộc tính sau:

  • label: nội dung mô tả ngữ nghĩa của một Plane nhất định. Có thể là Wall, Floor, Ceiling hoặc Table.
  • centerPose: Tư thế của tâm mặt phẳng được phát hiện.
  • extents: Kích thước của mặt phẳng được phát hiện, tính bằng mét.
  • vertices: Danh sách các đỉnh của một đa giác lồi gần đúng với mặt phẳng.

Thực hiện kiểm thử va chạm với mặt phẳng

Kiểm thử va chạm là một phương thức tính toán giao điểm của một tia với các đối tượng mà phiên theo dõi. Một ứng dụng phổ biến của kiểm thử nhấn là trỏ vào một bảng và đặt một đối tượng tại vị trí đó. Việc kiểm thử lượt nhấn sẽ dẫn đến một danh sách các đối tượng nhấn. Nói cách khác, quy trình kiểm thử lượt nhấn không dừng lại ở lượt nhấn đối tượng đầu tiên. Tuy nhiên, thường thì bạn chỉ quan tâm đến đối tượng đầu tiên được nhấn của một loại nhất định.

Để thực hiện kiểm thử nhấn, hãy sử dụng Interaction.hitTest() với Ray:

val results = Interaction.hitTest(session, ray)
// When interested in the first Table hit:
val tableHit = results.firstOrNull {
  val trackable = it.trackable
  trackable is Plane && trackable.state.value.label == Plane.Label.Table
}

Liên kết nội dung với một vị trí cố định trong không gian

Để đặt vị trí cho các đối tượng ảo trong thế giới thực, hãy sử dụng Anchor. Đối tượng neo giúp ứng dụng của bạn theo dõi một vị trí cố định trong không gian thực.

Một neo được tạo bằng Pose. Neo này có thể được diễn giải tương ứng với Trackable hiện có hoặc không.

Tạo một neo tương ứng với một đối tượng có thể theo dõi

Khi một neo được tạo tương ứng với một Trackable, chẳng hạn như Plane, điều này sẽ khiến neo theo Trackable đính kèm khi di chuyển trong không gian.

val anchor = trackable.createAnchor(pose)

Tạo một neo không có Đối tượng có thể theo dõi

Cách tạo một neo không được đính kèm vào Trackable:

when (val result = Anchor.create(session, pose)) {
  is AnchorCreateSuccess -> // ...
  else -> // handle failure
}

Đính kèm một thực thể vào một neo

Để kết xuất một mô hình tại vị trí này, hãy tạo một GltfModel và đặt tư thế của mô hình đó thành tư thế của neo. Đảm bảo rằng mô hình bị ẩn khi TrackingState của neo là Stopped.

// renderSession is androidx.xr.core.Session
anchor.state.collect { state ->
  if (state.trackingState == TrackingState.Tracking) {
    gltfEntity.setPose(
      renderSession.perceptionSpace.transformPoseTo(state.pose, renderSession.activitySpace)
    )
  } else if (state.trackingState == TrackingState.Stopped) {
    entity.setHidden(true)
  }
}

Tìm hiểu về TrackingState

Mỗi Trackable có một TrackingState cần được kiểm tra trước khi sử dụng. TrackableTrackableStateTracking sẽ có Pose được hệ thống chủ động cập nhật. TrackablePaused có thể trở thành Tracking trong tương lai, trong khi TrackableStopped sẽ không bao giờ trở thành Tracking.

Duy trì một điểm neo trong suốt các phiên

Một neo không tồn tại sẽ biến mất sau khi một phiên bị huỷ. Bằng cách lưu trữ một neo, ứng dụng của bạn sẽ ghi nhớ vị trí của neo đó trong dữ liệu ứng dụng riêng tư. Bạn có thể truy xuất liên kết này trong một phiên tiếp theo và liên kết này được liên kết ở cùng một vị trí trên thế giới.

Để duy trì một neo, hãy sử dụng anchor.persist() như minh hoạ ở đây:

val uuid = anchor.persist()

Ứng dụng của bạn có thể truy xuất neo bằng cách sử dụng UUID trong một phiên trong tương lai:

when (val result = Anchor.load(session, uuid)) {
  is AnchorCreateSuccess -> // Loading was successful. The anchor is stored in result.anchor.
  else -> // handle failure
}

Khi bạn không cần neo nữa, hãy gọi unpersist(). Thao tác này sẽ xoá neo khỏi bộ nhớ của ứng dụng và khiến UUID đã cho không thể truy xuất được đối với các lệnh gọi đến Anchor.load().

Anchor.unpersist(session, uuid)

Ứng dụng của bạn cũng có thể yêu cầu danh sách tất cả các neo đã được duy trì và vẫn có trong bộ nhớ của ứng dụng:

val uuids = Anchor.getPersistedAnchorUuids(session)