Tuỳ chỉnh mô hình 3D trong ứng dụng

Các thiết bị XR được hỗ trợ
Hướng dẫn này giúp bạn xây dựng các trải nghiệm cho những loại thiết bị XR sau.
Thiết bị đeo đầu XR
Kính thông minh XR có dây

Trước khi tuỳ chỉnh mô hình 3D, trước tiên bạn cần thêm mô hình đó vào ứng dụng. Sau khi thêm mô hình 3D vào ứng dụng, bạn có thể cải thiện trải nghiệm trực quan và tương tác bằng cách tuỳ chỉnh cách mô hình 3D xuất hiện và di chuyển.

Ví dụ: bạn có thể phát và kiểm soát các ảnh động glTF được nhúng, truy cập và di chuyển các nút tạo nên mô hình của bạn, hoặc thậm chí tải các hoạ tiết tuỳ chỉnh và xác định các thuộc tính vật liệu để ghi đè các lưới nội bộ. Những khả năng này cho phép bạn thay đổi linh hoạt giao diện và hành vi của một đối tượng trong thời gian chạy.

Đối tượng 3D trong Android XR

Jetpack XR SDK hỗ trợ tiêu chuẩn mở glTF 2.0 của Khronos Group cho các mô hình 3D và kết xuất các đối tượng này bằng kỹ thuật kết xuất dựa trên vật lý (PBR) được chỉ định trong tiêu chuẩn glTF 2.0 (cùng với các phần mở rộng được hỗ trợ). glTF (Graphics Library Transmission Format) là một định dạng tệp tiêu chuẩn để truyền và tải các cảnh và mô hình 3D. Mô hình glTF bao gồm một cấu trúc phân cấp của các thành phần nội bộ.

Sau đây là các thành phần chính cần hiểu rõ:

  • Nút: Các nút này xác định cấu trúc và hệ thống phân cấp của mô hình. Mỗi nút có thể có vị trí, hướng xoay và tỷ lệ riêng.
  • Lưới: Hình học 3D có cấu trúc tạo nên hình dạng của một đối tượng 3D.
  • Chất liệu: Những chất liệu này xác định hình thức trực quan của các lưới, chẳng hạn như màu sắc, độ nhám hoặc cách chúng phản ứng với ánh sáng.
  • Hoạ tiết: Một thành phần hình ảnh (chẳng hạn như tệp PNG) mà bạn có thể áp dụng cho bề mặt của mô hình 3D để tạo các mẫu, màu sắc, chi tiết tuỳ chỉnh hoặc các hiệu ứng hình ảnh khác.
  • Ảnh động: Đây là các chuỗi hoặc đường ảnh động được xác định trước, chứa các thay đổi đối với từng nút và lưới để tạo hiệu ứng chuyển động theo thời gian.

Trong Jetpack Compose cho XR, bạn sẽ kết xuất các tệp này bằng SpatialGltfModel và theo dõi trạng thái tải và ảnh động của tệp bằng SpatialGltfModelState. Để biết thêm thông tin, hãy xem bài viết Thêm mô hình 3D vào ứng dụng.

Tạo ảnh động cho mô hình 3D

Mô hình 3D có thể có ảnh động được nhúng. Về nội bộ, ảnh động sử dụng trình lấy mẫu để xác định thời gian và giá trị của một chuyển động, đồng thời sử dụng các kênh để kết nối những chuyển động đó với các nút và lưới riêng lẻ. Ảnh động bộ xương và ảnh động vật liệu được tạo bằng KHR_animation_pointer tiện ích glTF được hỗ trợ trong Jetpack XR SDK.

Khi dùng Compose cho XR, để phát một ảnh động, hãy chỉ định tên của một bản nhạc cụ thể trong danh sách animations. Sử dụng animation.start() để bắt đầu phát. Bạn có thể chỉ định tốc độ, thời gian tìm kiếm và việc ảnh động có nên lặp lại hay không bằng cách sử dụng SpatialGltfModelAnimation:

val animation = modelState.animations.find { it.name == "Walk" }

animation?.animationState?.let { state ->
    LaunchedEffect(state) {
        Log.i("SpatialGltfModelAnimationSample", "Animation State: $state")
    }
}

DisposableEffect(animation) {
    animation?.loop()
    onDispose {
        animation?.stop()
    }
}

Thao tác với các nút: Tư thế và hướng xoay

Để thao tác với các phần cụ thể của một mô hình và thay đổi các thuộc tính của mô hình đó, chẳng hạn như hướng xoay hoặc tư thế, bạn sẽ cần truy vấn nodes nội bộ của mô hình glTF bằng cách sử dụng SpatialGltfModelState.

// Retrieve the list of nodes (individual components/meshes) defined within the glTF model.
val entityNodes = modelState.nodes

// Find a specific node by name to apply modifications, such as material overrides.
val node = entityNodes.find { it.name == "node_name" }

Sau khi tìm thấy nút chính xác, bạn có thể đặt localPose để thay đổi vị trí và hướng xoay 3D của nút đó so với GltfModelNode gốc mẹ ngay lập tức hoặc sử dụng modelPose để đặt vị trí so với gốc GltfModelEntity. Tương tự, bạn có thể sử dụng localScale/modelScale để thay đổi tỷ lệ của mô hình so với đối tượng gốc hoặc gốc.

LaunchedEffect(node, degrees) {
    val rotation = Quaternion.fromEulerAngles(degrees, 0f, degrees)
    node?.let {
        it.localPose = Pose(it.localPose.translation, rotation)
    }
}

Tuỳ chỉnh các thuộc tính vật liệu của mô hình 3D

Bạn có thể điều chỉnh các thuộc tính của vật liệu trong thời gian chạy để thay đổi giao diện của một đối tượng một cách linh hoạt dựa trên hoạt động đầu vào của người dùng hoặc trạng thái hiện tại của ứng dụng.

Trong Jetpack XR, các lớp KhronosPbrMaterialKhronosUnlitMaterial được dùng để tạo và thao tác với các vật liệu này. Như tên gọi của nó, KhronosUnlitMaterials không được chiếu sáng và không chịu ảnh hưởng của ánh sáng trong cảnh. KhronosPbrMaterial cho phép bạn tuỳ chỉnh nhiều thuộc tính hơn, chẳng hạn như màu sắc bóng, độ bóng hoặc độ thô của một đối tượng và liệu đối tượng đó có phát ra ánh sáng hay không.

Để biết thêm thông tin về từng thuộc tính được hỗ trợ và các tham số có thể tuỳ chỉnh trong Android XR, hãy xem tài liệu tham khảo của chúng tôi. Để hiểu rõ hơn về các thuộc tính này, hãy xem bảng thuật ngữ của Khronos.

Hình 1. Ví dụ về cách thay đổi màu cơ bản trên mô hình 3D.

Để tuỳ chỉnh các thuộc tính vật liệu của mô hình 3D, trước tiên, bạn sẽ tạo vật liệu mới bằng cách sử dụng KhronosPbrMaterial. Bạn cần đặt AlphaMode thích hợp cho giao diện mà bạn đang cố gắng đạt được:

Tiếp theo, hãy xác định những thuộc tính mà bạn muốn sửa đổi. Ví dụ này sử dụng setBaseColorFactor để thay đổi màu cơ bản của lưới thành màu tím. Phương thức này yêu cầu một Vector4, trong đó các thành phần x, y, zw tương ứng với các giá trị RGBA (Đỏ, Lục, Lam và Alpha):

// Maintain a reference to the custom material to avoid re-creating it on every recomposition.
var pbrMaterial by remember { mutableStateOf<KhronosPbrMaterial?>(null) }

// Create and apply the custom material once the session is ready and the target node is available.
LaunchedEffect(node) {
    val material = KhronosPbrMaterial.create(
        session = xrSession,
        alphaMode = AlphaMode.OPAQUE
    ).also {
        pbrMaterial = it
        // Apply a base color factor (RGBA) to change the color of the model.
        it.setBaseColorFactor(
            Vector4(
                x = 0.5f,
                y = 0.0f,
                z = 0.5f,
                w = 1.0f
            )
        )
    }

Tải các hoạ tiết tuỳ chỉnh cho mô hình 3D

Texture là một thành phần hình ảnh mà bạn có thể áp dụng cho bề mặt của một mô hình 3D để cung cấp màu sắc, chi tiết hoặc thông tin khác về bề mặt. Jetpack XR Texture API cho phép bạn tải dữ liệu hình ảnh (chẳng hạn như tệp PNG) từ thư mục /assets/ của ứng dụng một cách không đồng bộ.

Khi tải một hoạ tiết, bạn có thể chỉ định một TextureSampler, giúp kiểm soát cách hoạ tiết được hiển thị. Bộ lấy mẫu xác định các thuộc tính lọc (khi hoạ tiết xuất hiện nhỏ hơn hoặc lớn hơn kích thước ban đầu) và các chế độ bao bọc (để xử lý các toạ độ bên ngoài phạm vi [0, 1] tiêu chuẩn). Bạn phải chỉ định một Texture cho một KhronosPbrMaterial để có hiệu ứng hình ảnh trên mô hình 3D.

Hình 2. Ví dụ về cách thay đổi hoạ tiết trên mô hình 3D.

Để tải một hoạ tiết tuỳ chỉnh, trước tiên, bạn cần lưu tệp hình ảnh vào thư mục /assets/. Cách tốt nhất là bạn cũng nên tạo một thư mục con textures trong thư mục đó.

Sau khi bạn lưu tệp vào thư mục thích hợp, hãy tạo hoạ tiết bằng API Texture. Đây cũng là nơi bạn sẽ áp dụng TextureSampler không bắt buộc (nếu cần).

Ví dụ này áp dụng một hoạ tiết che khuất và đặt độ mạnh che khuất:

LaunchedEffect(node) {
    val material = KhronosPbrMaterial.create(
        session = xrSession,
        alphaMode = AlphaMode.OPAQUE
    ).also {
        pbrMaterial = it

        // Load a texture
        val texture = Texture.create(
            session = xrSession,
            path = Path("textures/texture_name.png")
        )

        // Set the texture and configure occlusion to define how the material surface handles ambient lighting.
        it.setOcclusionTexture(
            texture = texture,
            strength = 1.0f
        )
    }
    node?.setMaterialOverride(
        material = material
    )
}

Áp dụng vật liệu và hoạ tiết cho các đối tượng 3D

Để áp dụng chất liệu hoặc hoạ tiết mới, hãy ghi đè chất liệu hiện có cho một nút cụ thể trên node glTF. Thực hiện việc này bằng cách gọi setMaterialOverride:

node?.setMaterialOverride(
    material = material
)

Để xoá các thành phần mới tạo, hãy gọi clearMaterialOverride trên nút bị ghi đè trước đó. Thao tác này sẽ đưa Mô hình 3D về trạng thái mặc định:

if (removeMaterial) {
    node?.clearMaterialOverride()
}


glTF và biểu trưng glTF là các nhãn hiệu của Khronos Group Inc.