Tối ưu hóa hiệu năng của giao diện người dùng (UI) mang lại trải nghiệm mượt mà cho người chơi. Trong bài viết này, chúng ta sẽ cùng khám phá một số kỹ thuật tối ưu UI cơ bản trong Unity. Những hướng dẫn này giúp cải thiện hiệu năng game, giảm thiểu lãng phí tài nguyên hệ thống, đảm bảo game chạy trơn tru trên nhiều thiết bị.
Nội dung
Tối ưu Sprite Atlas
Hãy bắt đầu với thần chú đầu tiên để tối ưu UI cơ bản trong Unity.
Việc sử dụng Sprite Atlas có hai lợi ích chính:
- Tối ưu draw call. Draw call là một lần gọi lệnh đến thư viện đồ hoạ để vẽ một vật. Một draw call tiêu tốn nhiều tài nguyên để xử lý nên nếu số lượng draw call lớn gây ảnh hưởng nhiều đến hiệu năng game. Với Sprite Atlas, chỉ cần một draw call duy nhất để vẽ tất cả các ảnh nằm trong một atlas giúp giảm số lượng draw call cần thiết để vẽ nhiều ảnh.
- Giảm thiểu việc GPU phải xử lý ảnh Non-Power of 2 (NPOT) bằng cách gom nhiều ảnh NPOT vào một tấm atlas đảm bảo Power of 2 (POT). Việc xử lý ảnh NPOT khiến GPU phải padding gây tốn vRAM. Ví dụ ảnh 13×12 sẽ được padding thành 16×16, lãng phí diện tích 3×4. Nếu sử dụng Sprite Atlas, ta có thể ghép hai ảnh 13×12 và 3×4 lại thành một tấm atlas 16×16.
Khi packing atlas, bạn cần phải thật cẩn trọng, tỉ mỉ trong việc quyết định những ảnh nào sẽ thuộc cùng một atlas. Chỉ cần một ảnh trong atlas được sử dụng, cả tấm atlas sẽ được load vào trong RAM. Nếu packing không hợp lý sẽ dẫn đến tình trạng lãng phí RAM. Nguyên nhân do load thừa những ảnh chưa cần sử dụng. Sau đây là một số quy tắc đơn giản để có thể packing atlas một cách hiệu quả. Khi sử dụng bạn sẽ tránh được các lãng phí tài nguyên của thiết bị:
- Tạo một tấm atlas chung chứa các ảnh liên tục được hiển thị trên màn hình như tấm nền panel, coin icon,…
- Tạo atlas riêng cho từng view trong game. Những ảnh dùng chung giữa nhiều view thì tách riêng ra một atlas khác.
- Không pack những ảnh lớn như background vào atlas. Nếu đóng gói một tấm background 1800×1000 và atlas Full HD 1920×1080 thì một tấm atlas gần như chỉ chứa được một tấm background duy nhất, làm mất ý nghĩa của giảm draw call.
- Không đóng gói vào atlas với những ảnh có tần suất sử dụng thấp và hiển thị rời rạc với các thành phần UI khác trong game. Ví dụ UI hòm quà hiện ngẫu nhiên trong game với tỷ lệ xuất hiện 2% mỗi lần chơi.
Tối ưu Texture Settings
Những thứ bạn cần cân nhắc khi chọn thiết lập cho texture:
- Tắt Generating of Physics Shapes với những ảnh không cần nhận input từ người dùng (không cần raycast).
- Sử dụng ảnh có kích thước là mũ của 2 (POT) như 16×16, 16×32,… để tránh việc GPU phải padding texture trước khi xử lý.
- Tắt kênh alpha với những ảnh không cần trong suốt như background.
- Sử dụng mipmap với những game có sự thay đổi khoảng cách từ camera đến vật thể (game có khả năng zoom in, zoom out). Dùng mipmap giảm vRAM sử dụng khi chạy, nhưng khiến dung lượng file build nặng hơn do phải chứa các version với kích thước khác nhau của cùng một tấm ảnh.
- Thay đổi max texture size để tránh sử dụng ảnh có kích thước lớn hơn cần thiết.
- Lựa chọn texture compression, texture format phù hợp với từng platform.
- Sử dụng 9-slice với các thành phần UI như panel, button,…
Tối ưu Canvas
Canvas là một game object có component Canvas chứa tất cả các phần tử UI. Canvas chịu trách nhiệm tổng hợp các thông tin như texture, material, shader, mesh của tất cả các phần tử UI trong nó, từ đó đẩy draw call đến GPU để hiển thị UI lên màn hình. Một số quy tắc để tối ưu canvas:
- Chia view của bạn thành các Canvas khác nhau (khi một thành phần bất kỳ thay đổi trên Canvas UI, nó sẽ làm dirty toàn bộ Canvas khiến cả Canvas phải vẽ lại). Do đó nên giữ các UI tĩnh (Info panel) trên một Canvas riêng biệt với các UI động (UI có animation, thay đổi liên tục như đồng hồ đếm ngược).
- Khi một canvas được mở toàn màn hình, hãy disable các canvas không được hiển thị vì Unity tiếp tục render tất cả canvas dù không nhìn thấy gây lãng phí tài nguyên hệ thống.
- Ưu tiên tắt canvas bằng thuộc tính enable thay vì SetActive game object để tránh việc phải vẽ lại toàn bộ canvas mỗi khi bật tắt.
- Giữ cây game object của UI càng ít tầng càng tốt để giảm thiểu giảm thiểu độ nặng mỗi lần vẽ lại canvas.
Tối ưu Raycast Target
Raycaster chuyển tương tác của người dùng thành UI Events trong Unity. Sau đó gửi chúng đến các hệ thống code quan tâm. Bạn cần có Graphic Raycaster trên các Canvas cần lắng nghe input của người dùng. Với những UI không cần nghe input của người dùng như Text Name (hiện tên của người dùng), nếu vẫn enable Raycast Target sẽ khiến Unity phải kiểm tra Text Name có đang được người dùng tương tác hay không, dẫn đến lãng phí CPU.
Vậy nên bất cứ UI nào không quan tâm đến input của người dùng, hãy tắt Raycast Target. Trên các view lớn có hàng ngàn phần tử UI, việc này sẽ giúp tiết kiệm rất nhiều hiệu năng CPU.
Tối ưu Layout Groups
Tránh sử dụng LayoutGroup (Vertical Layout, Horizontal Layout, Grid Layout) nếu không thật sự cần thiết. Khi một hoặc nhiều phần tử UI con thay đổi trên layout, layout sẽ trở nên dirty. Mỗ phần tử UI khiến layout dirty sẽ thực hiện tối thiểu một lệnh gọi GetComponents. Lệnh GetComponent được gọi để tìm component LayoutGroup trên game object cha. Việc này lặp lại liên tục đến khi không còn tìm được LayoutGroup nào ở game object cha nữa.
Do đó, mỗi LayoutGroup component sẽ thêm một lệnh gọi GetComponents vào quá trình vẽ lại canvas, khiến cho các LayoutGroup lồng nhau có hiệu suất cực kỳ kém.
Sử dụng Anchor để neo các phần tử UI với layout đơn giản mà không cần dùng Layout Group. Nếu UI có nhiều phần tử động, cân nhắc tự viết code để tính toán vị trí các phần tử, đảm bảo chỉ gọi lệnh tính toán vị trí khi cần thiết, thay vì gọi mỗi lần có thay đổi xảy ra.
Tối ưu Animation
Chỉ sử dụng Animator cho UI animation với những phần tử thay đổi liên tục khi hiển thị. Lý do bởi vì Animator sẽ làm dirty các thành phần UI của Animator đó mỗi frame, ngay cả khi giá trị trong animation không thay đổi.
Với những thành phần UI ít khi thay đổi, hoặc chỉ thay đổi trong thời gian ngắn khi một sự kiện xảy ra thì nên sử dụng các thư viện Tweening như DOTween để làm animation.
Tổng kết
Việc tối ưu UI cơ bản trong Unity là một bước quan trọng giúp nâng cao hiệu suất game, đảm bảo trải nghiệm người chơi luôn mượt mà và hấp dẫn. Qua bài viết này, chúng ta đã tìm hiểu cách sử dụng Sprite Atlas để giảm draw call và tiết kiệm vRAM, tối ưu hóa Texture Settings và giảm thiểu việc sử dụng Layout Groups không cần thiết,…
Để nắm vững các kỹ thuật này và nhiều kiến thức bổ ích khác, đừng quên tham gia khóa học lập trình Game Unity tại CodeGym. Bạn sẽ được trang bị đầy đủ kỹ năng để trở thành một Game developer chuyên nghiệp.
0 Lời bình