Mô-Đun Quản Lý Texture Và Mô Hình 3D Trên Giao Diện Người Dùng
Giao diện người dùng (UI) trong động cơ game của chúng tôi được xây dựng dựa trên công nghệ tương tự như HTML/CSS, cụ thể là phiên bản fork và tự phát triển từ RmlUI. Một yêu cầu phổ biến trong các dự án game hiện tại là tích hợp mô hình 3D như một thành phần UI. Tôi đã từng gặp yêu cầu này trong nhiều dự án trước đây và chứng kiến nhiều cách tiếp cận khác nhau tùy theo động cơ game.
Trong các game nhập vai (RPG), bảng thông tin nhân vật thường yêu cầu hiển thị mô hình 3D có thể xoay 360 độ. Dù dự án hiện tại mang phong cách Factorio không có avatar, nhưng khi mở bảng thông tin công trình, chúng tôi cũng cần hiển thị mô hình 3D động của công trình đó.
Ban đầu, chúng tôi giải quyết vấn đề này bằng cách render mô hình 3D đè lên lớp UI mà không tích hợp sâu với RmlUI. Phương pháp này tạo ra “cửa hậu” khi UI chỉ cần chừa trống vị trí, sau đó mô hình 3D sẽ được render chồng lên. Tuy nhiên, cách làm này khiến mô hình 3D không có cấu trúc phân tầng đồng nhất với các thành phần UI, dẫn đến nhiều vấn đề về thứ tự hiển thị và tương tác.
Để cải thiện, chúng tôi đã tạo một render target riêng và sửa đổi RmlUI để hỗ trợ canvas dạng hình chữ nhật. Điều này giúp mô hình 3D hòa hợp hơn với hệ thống UI, nhưng đòi hỏi phải viết mã quản lý riêng cho các thành phần 3D, đặc biệt là vòng đời của render target.
Gần đây, khi muốn tích hợp thêm nhiều mô hình 3D thay thế hình ảnh 2D truyền thống, chúng tôi nhận ra cần một giải pháp tổng thể hơn. Từ góc nhìn UI, những mô hình này nên được coi như hình ảnh thông thường, dù nguồn gốc của chúng không phải file ảnh mà là kết quả render thời gian thực từ engine 3D. Việc tiếp tục dùng phương pháp hiện tại sẽ làm tăng chi phí bảo trì các ảnh pre-render, trong khi giải pháp tạm thời trước đó không đủ sức đáp ứng yêu cầu mới.
May mắn thay, chúng tôi vừa hoàn thành việc tái cấu trúc mô-đun quản lý texture. Toàn bộ texture trong engine giờ đây được quản lý tập trung qua một máy ảo Lua duy nhất trong cùng một luồng xử lý. Ý tưởng đột phá nảy ra là: Nếu UI coi mô hình 3D như một hình ảnh, thì chúng thực chất là texture chứ không phải canvas. Thay vì dùng đường dẫn file như trước, chúng tôi chuyển sang cơ chế URI (Uniform Resource Identifier) quen thuộc trong công nghệ web.
Cơ chế mới cho phép chỉ định nguồn gốc texture qua tiền tố giao thức. Ví dụ:
file://assets/texture.png
- Lấy từ hệ thống tệphttp://server.com/dynamic.jpg
- Tải từ serverrender://character_preview
- Yêu cầu render từ engine 3D
Chi tiết tái cấu trúc mô-đun quản lý texture:
-
Hệ thống handle gián tiếp:
- Trước đây: Handle texture là trực tiếp bgfx::TextureHandle
- Hiện tại: Handle trở thành ID gián tiếp, cần chuyển đổi qua C API để lấy bgfx::TextureHandle thực tế khi render
-
Dịch vụ quản lý đa luồng (ltask):
- Cho phép tạo handle texture tức thì
- Dữ liệu texture được tải bất đồng bộ
- Giai đoạn đầu sử dụng texture thay thế (solid color)
- Sau vài frame, texture thật sẽ thay thế tự động
- Áp dụng thuật toán LRU để dọn dẹp texture không dùng
-
Cơ chế URI linh hoạt:
- Mỗi texture được đánh chỉ số bằng chuỗi URI
- Khi cần tải lại texture đã bị dọn, hệ thống tự động nhận diện qua URI
- Hỗ trợ nhiều giao thức tùy chỉnh (render://, video://, v.v.)
Ứng dụng thực tế:
Khi hiển thị mô hình 3D trên UI, RmlUI chỉ cần yêu cầu texture với URI render://building_001
. Mô-đun quản lý texture sẽ tự động chuyển yêu cầu này đến dịch vụ render tương ứng. Các thông số như góc nhìn camera, ánh sáng… được thiết lập riêng biệt thông qua CSS hoặc hệ thống cài đặt game, không cần nhúng vào URI.
Mở rộng tương lai:
Cơ chế này không giới hạn ở texture tĩnh. Dù là ảnh động thay đổi từng frame hay video stream, RmlUI đều xử lý đồng nhất bằng cách thay đổi giao thức URI. Ví dụ: video://cutscene_ending
sẽ kích hoạt trình phát video mà không cần thay đổi kiến trúc UI.
Giải pháp này không chỉ giải quyết bài toán hiện tại mà còn mở ra khả năng tích hợp các nguồn tài nguyên động khác trong tương lai, giúp hệ thống UI trở nên linh hoạt và mở rộng vô hạn.