Tạo, kiểm soát và quản lý thực thể

SDK Jetpack XR cho phép bạn dùng Jetpack SceneCore để tạo, kiểm soát và quản lý các thực thể Entity như mô hình 3D, video lập thểPanelEntity bằng Jetpack SceneCore.

Jetpack SceneCore áp dụng 2 mẫu kiến trúc phổ biến để hỗ trợ quá trình phát triển 3D: biểu đồ cảnhhệ thống thành phần thực thể (ECS).

Sử dụng biểu đồ cảnh để tạo và kiểm soát các thực thể

Để tạo và kiểm soát các đối tượng trong không gian 3D, bạn có thể sử dụng API Session của Jetpack SceneCore để có quyền truy cập vào biểu đồ cảnh. Biểu đồ cảnh phù hợp với thế giới thực của người dùng và cho phép bạn sắp xếp các thực thể 3D như bảng điều khiển và mô hình 3D thành một cấu trúc phân cấp, đồng thời giữ trạng thái của các thực thể đó.

Sau khi có quyền truy cập vào biểu đồ cảnh, bạn có thể dùng các API trong Jetpack Compose cho XR để tạo giao diện người dùng không gian (ví dụ: các thực thể SpatialPanelOrbiter) trong biểu đồ cảnh. Đối với nội dung 3D như mô hình 3D, bạn có thể truy cập trực tiếp vào Phiên. Để tìm hiểu thêm, hãy xem phần Giới thiệu về ActivitySpace trên trang này.

Hệ thống thành phần thực thể

Hệ thống thành phần thực thể tuân theo nguyên tắc kết hợp thay vì kế thừa. Bạn có thể mở rộng hành vi của các thực thể bằng cách đính kèm các thành phần xác định hành vi. Nhờ đó, bạn có thể áp dụng cùng một hành vi cho nhiều loại thực thể. Để biết thêm thông tin, hãy xem phần Thêm hành vi chung cho các thực thể trên trang này.

Giới thiệu về ActivitySpace

Mỗi Session đều có một ActivitySpace được tạo tự động bằng Session. ActivitySpaceEntity cấp cao nhất trong biểu đồ cảnh.

ActivitySpace biểu thị một không gian 3 chiều với hệ toạ độ thuận tay phải (trục x hướng sang phải, trục y hướng lên trên và trục z hướng về phía sau so với gốc) và có đơn vị là mét, phù hợp với thế giới thực. Nguồn gốc của ActivitySpace có phần tuỳ ý (vì người dùng có thể đặt lại vị trí của ActivitySpace trong thế giới thực), do đó, bạn nên định vị nội dung tương ứng với nhau thay vì tương ứng với nguồn gốc.

Làm việc với các thực thể

Các thực thể là yếu tố trung tâm của SceneCore. Hầu hết mọi thứ mà người dùng nhìn thấy và tương tác đều là các thực thể đại diện cho bảng điều khiển, mô hình 3D và nhiều nội dung khác.

ActivitySpace là nút cấp cao nhất của biểu đồ cảnh, theo mặc định, tất cả các thực thể mới sẽ được đặt trực tiếp vào ActivitySpace. Bạn có thể di chuyển các thực thể dọc theo biểu đồ cảnh bằng cách đặt parent hoặc bằng cách sử dụng addChild().

Các thực thể có một số hành vi mặc định đối với những đối tượng phổ biến với tất cả các thực thể, chẳng hạn như thay đổi vị trí, chế độ xoay hoặc khả năng hiển thị. Các lớp con Entity cụ thể, chẳng hạn như GltfModelEntity, có thêm các hành vi hỗ trợ lớp con.

Thao tác với thực thể

Khi bạn thay đổi một thuộc tính Entity thuộc lớp Entity cơ sở, thay đổi đó sẽ được áp dụng cho tất cả các thành phần con của lớp đó. Ví dụ: việc điều chỉnh Pose của một Entity mẹ sẽ dẫn đến việc tất cả các thành phần con của thành phần đó đều có cùng một mức điều chỉnh. Việc thay đổi một Entity con sẽ không ảnh hưởng đến Entity gốc.

Pose đại diện cho vị trí và hướng xoay của Thực thể trong không gian 3D. Vị trí là Vector3 bao gồm các vị trí số x, y, z. Góc xoay được biểu thị bằng Quaternion. Vị trí của Entity luôn tương ứng với thực thể mẹ. Nói cách khác, Entity có vị trí (0, 0, 0) sẽ được đặt tại gốc của thực thể mẹ.

// Place the entity forward 2 meters
val newPosition = Vector3(0f, 0f, -2f)
// Rotate the entity by 180 degrees on the up axis (upside-down)
val newOrientation = Quaternion.fromEulerAngles(0f, 0f, 180f)
// Update the position and rotation on the entity
entity.setPose(Pose(newPosition, newOrientation))

Để tắt Entity, hãy sử dụng setEnabled(). Thao tác này sẽ ẩn đối tượng và dừng mọi quy trình xử lý được thực hiện trên đối tượng đó.

// Disable the entity.
entity.setEnabled(false)

Để đổi kích thước Entity mà vẫn giữ nguyên hình dạng tổng thể, hãy sử dụng setScale().

// Double the size of the entity
entity.setScale(2f)

Thêm hành vi chung vào các thực thể

Bạn có thể sử dụng các thành phần sau để thêm hành vi chung vào các thực thể:

  • MovableComponent: Cho phép người dùng di chuyển các thực thể
  • ResizableComponent: Cho phép người dùng đổi kích thước các thực thể bằng các mẫu giao diện người dùng nhất quán
  • InteractableComponent: Cho phép bạn ghi lại các sự kiện đầu vào cho các lượt tương tác tuỳ chỉnh

Bạn phải thực hiện việc khởi tạo các thành phần thông qua phương thức tạo thích hợp trong lớp Session. Ví dụ: để tạo một ResizableComponent, hãy gọi ResizableComponent.create().

Để thêm hành vi của thành phần cụ thể vào Entity, hãy sử dụng phương thức addComponent().

Sử dụng MovableComponent để làm cho Người dùng thực thể có thể di chuyển

MovableComponent cho phép người dùng di chuyển Entity.

Các sự kiện di chuyển được gửi đến thành phần khi người dùng tương tác với các thành phần trang trí. Hành vi mặc định của hệ thống (được tạo bằng MovableComponent.createSystemMovable()) sẽ di chuyển Entity khi các thành phần trang trí được kéo:

val movableComponent = MovableComponent.createSystemMovable(session)
entity.addComponent(movableComponent)

Tham số scaleInZ không bắt buộc (theo mặc định, được đặt thành true) sẽ khiến Thực thể tự động điều chỉnh tỷ lệ khi di chuyển ra xa người dùng, tương tự như cách hệ thống điều chỉnh tỷ lệ các bảng trong không gian chính. Do tính chất "xếp tầng" của hệ thống thành phần thực thể, tỷ lệ của thực thể mẹ sẽ ảnh hưởng đến tất cả các thực thể con.

Bạn cũng có thể chỉ định xem thực thể có thể được cố định vào một loại bề mặt như bề mặt ngang hoặc dọc, hay các bề mặt ngữ nghĩa cụ thể như bàn, tường hoặc trần nhà hay không. Để chỉ định các lựa chọn về điểm neo, hãy chỉ định một nhóm AnchorPlacement khi tạo MovableComponent. Trong ví dụ này, thực thể có thể di chuyển và cố định vào bất kỳ bề mặt ngang nào của sàn nhà hoặc bàn:

val anchorPlacement = AnchorPlacement.createForPlanes(
    anchorablePlaneOrientations = setOf(PlaneOrientation.VERTICAL),
    anchorablePlaneSemanticTypes = setOf(PlaneSemanticType.FLOOR, PlaneSemanticType.TABLE)
)

val movableComponent = MovableComponent.createAnchorable(
    session = session,
    anchorPlacement = setOf(anchorPlacement)
)
entity.addComponent(movableComponent)

Sử dụng ResizableComponent để cho phép người dùng đổi kích thước Thực thể

ResizableComponent cho phép người dùng đổi kích thước một Entity. ResizableComponent bao gồm các tín hiệu tương tác trực quan mời người dùng đổi kích thước một Entity. Khi tạo ResizableComponent, bạn có thể chỉ định kích thước tối thiểu hoặc tối đa (tính bằng mét). Bạn cũng có thể chỉ định một tỷ lệ khung hình cố định khi đổi kích thước để chiều rộng và chiều cao đổi kích thước tương ứng với nhau.

Khi tạo một ResizableComponent, hãy chỉ định một resizeEventListener xử lý các sự kiện cập nhật. Bạn có thể phản hồi các sự kiện ResizeState khác nhau, chẳng hạn như RESIZE_STATE_ONGOING hoặc RESIZE_STATE_END.

Sau đây là ví dụ về cách sử dụng ResizableComponent với tỷ lệ khung hình cố định trên SurfaceEntity:

val resizableComponent = ResizableComponent.create(session) { event ->
    if (event.resizeState == ResizeEvent.ResizeState.RESIZE_STATE_END) {
        // update the Entity to reflect the new size
        surfaceEntity.canvasShape = SurfaceEntity.CanvasShape.Quad(event.newSize.width, event.newSize.height)
    }
}
resizableComponent.minimumEntitySize = FloatSize3d(177f, 100f, 1f)
resizableComponent.fixedAspectRatio = 16f / 9f // Specify a 16:9 aspect ratio

surfaceEntity.addComponent(resizableComponent)

Sử dụng InteractableComponent để ghi lại các sự kiện nhập của người dùng

InteractableComponent cho phép bạn ghi lại các sự kiện đầu vào của người dùng, chẳng hạn như khi người dùng tương tác hoặc di chuột lên một Entity. Khi tạo một InteractableComponent, hãy chỉ định một trình nghe nhận các sự kiện đầu vào. Khi người dùng thực hiện bất kỳ thao tác nhập nào, trình nghe sẽ được gọi bằng thông tin đầu vào được cung cấp trong tham số InputEvent.

Để biết danh sách đầy đủ tất cả các hằng số InputEvent, hãy xem tài liệu tham khảo.

Đoạn mã sau đây cho thấy một ví dụ về cách sử dụng InteractableComponent để tăng kích thước của một thực thể bằng tay phải và giảm kích thước bằng tay trái.

val executor = Executors.newSingleThreadExecutor()
val interactableComponent = InteractableComponent.create(session, executor) {
    // when the user disengages with the entity with their hands
    if (it.source == InputEvent.Source.SOURCE_HANDS && it.action == InputEvent.Action.ACTION_UP) {
        // increase size with right hand and decrease with left
        if (it.pointerType == InputEvent.Pointer.POINTER_TYPE_RIGHT) {
            entity.setScale(1.5f)
        } else if (it.pointerType == InputEvent.Pointer.POINTER_TYPE_LEFT) {
            entity.setScale(0.5f)
        }
    }
}
entity.addComponent(interactableComponent)