Tối ưu hóa hiệu suất cho Game D trong Unity (Phần 1)

11:20 11/12/2024

Unity 3D là công cụ phát triển game mạnh mẽ và phổ biến, nhưng để tạo ra trò chơi 3D với hiệu suất cao, việc tối ưu hóa là cực kỳ quan trọng. Trong bài viết này, FPT Polytechnic Hà Nội sẽ hướng dẫn cách tối ưu hóa các yếu tố quan trọng như mô hình 3D, textures, ánh sáng và sử dụng công cụ tích hợp của Unity để đạt được hiệu suất tối ưu.

Tối ưu hóa mô hình 3D

Mô hình 3D là yếu tố quan trọng ảnh hưởng trực tiếp đến hiệu suất game. Dưới đây là một số cách giúp bạn tối ưu hóa mô hình:

  • Giảm số lượng polygons:

Đối với mỗi mô hình, số lượng polygons (đa giác) ảnh hưởng trực tiếp đến số lần tính toán khi render. Bạn hãy cố gắng điều chỉnh để sử dụng số polygons tối thiểu mà vẫn giữ được chất lượng hình ảnh. Trong Unity, cũng như nhiều công cụ game engine khác, mô hình 3D được tính bằng tam giác (triangle)đỉnh (vertex), thay vì sử dụng đa giác (polygon). Trong phần mềm 3D (như Blender, Maya), các mô hình thường được xây dựng từ polygons, thường là quads (4 cạnh) hoặc nhiều cạnh hơn. Các polygon này dễ làm việc trong quá trình dựng hình và chỉnh sửa mô hình vì chúng giúp giữ được bề mặt phẳng hoặc dễ dàng áp dụng texture và ánh sáng.

Khi mô hình được import vào Unity (hoặc hầu hết các game engine), mọi polygon đều được chuyển đổi thành các tam giác. Điều này xảy ra vì: Tam giác là đơn vị cơ bản nhất để GPU xử lý. Tất cả phần cứng đồ họa hiện nay đều sử dụng tam giác để dựng hình, vì tam giác là đa giác duy nhất luôn phẳng bất kể vị trí của đỉnh. Vì vậy, một quad (đa giác 4 cạnh) được chia thành 2 tam giác để đơn giản hóa tính toán render.

Các lưới được chia thành các hình tam giác trong Unity

Tùy vào nền tảng mục tiêu mà bạn nên hạn chế số lượng lưới tam giác (tris) như: mobile thì các đối tượng chính nên có số lưới từ 1.5K – 5K và các đối tượng phụ, môi trường khoảng 300 – 1.5K; đối với PC/Console thì các đối tượng chính có thể lên tới 10K – 20K hoặc hơn, tùy vào mục tiêu của game. Số liệu trên không phải là bắt buộc cố định mà có thể thay đổi nhiều ít tùy vào kiểu mô hình, đồ họa game mong muốn, và sự phát triển của phần cứng.

  • Tối ưu hóa Batches: Batches là số lượng lệnh draw call để render các đối tượng lên màn hình. Số lượng batches cao sẽ gây ảnh hưởng đến hiệu suất, vì mỗi batches là một lệnh riêng biệt cho CPU và GPU xử lý. Đối với các thiết bị di động, bạn nên giữ số batches khoảng 100-150 cho mỗi khung hình, PC/Console khoảng 100 – 500 hoặc hơn tùy vào độ phức tạp của cảnh và sức mạnh phần cứng. Có 1 vài cách để tối ưu hóa Batches như:
Xem số Batches trong Stats của cửa sổ Game
    • Áp dụng Static Batching đối với các đối tượng tĩnh như nhà cửa, cây cối, nền đất…). Bật Static trong cửa sổ Inspector với các đối tượng bạn muốn áp dụng Static Batching. Lưu ý: các đối tượng này phải cùng vật liệu (materials), khi sử dụng Static Batching thì game của bạn có thể sẽ nặng hơn vì Unity sẽ tạo 1 bản sao của tất cả các đối tượng đã batch, vì vậy bạn không nên áp dụng cách này cho các đối tượng quá lớn.
    • Áp dụng Dynamic Batching đối với các đối tượng nhỏ và có thể di chuyển. Cài đặt này thường được tự động bật và Unity sẽ tự động nhóm các đối tượng di chuyển lại với nhau nếu chúng có cùng kích thước và vật liệu. Bạn có thể tìm thấy cài đặt này trong menu Edit > Project Setting > Player > Other Setting > Dynamic Batching
    • Sử dụng Texture Atlasing: kết hợp nhiều texture thành 1 texture lớn.
    • Unity có hỗ trợ Level of Detail (LOD), cho phép sử dụng các phiên bản mô hình đơn giản hơn khi vật thể ở xa người chơi, tiết kiệm tài nguyên khi render các đối tượng không quan trọng. Hãy sử dụng Maya hoặc Blender để tạo ra các bản sao của model, sau đó giảm số lượng lưới của các bản sao này xuống.

Ở 3 hình trên, lần lượt là LOD1, LOD2, LOD3 với số lượng lưới giảm dần. Bạn có thể thấy LOD3 đã bị vỡ hình, nhưng chúng ta vẫn sẽ sử dụng LOD3 trong các trường hợp nhìn từ xa và chỉ cần thấy dáng của nhân vật.

    • Đưa model vào Unity và thiết lập LOD, chúng ta hãy cùng xem qua việc hiển thị của nhân vật tùy vào độ xa gần của camera như thế nào. Trước tiên là LOD1, trong hình dưới các bạn có thể thấy khi camera ở gần LOD1 được render và hình ảnh nhân vật sắc nét.
    • Khi camera kéo ra xa 1 chút và sang phần LOD2 thì LOD1 bị ẩn và LOD2 hiện ra. Lúc này bạn có thể thấy nhân vật đã bị vỡ vì số lưới của LOD2 đã bị giảm trước đó trong phần mềm Blender. Lưu ý: trong ví dụ này chúng ta kéo khoảng cách xuất hiện của LOD2 ngắn lại để kiểm tra cách hoạt động của LOD. 
    • Tiếp tục kéo camera ra xa khỏi đối tượng thì LOD3 xuất hiện, LOD1 và LOD2 bị ẩn đi. Lúc này các bạn có thể thấy nhân vật hoàn toàn bị vỡ vì LOD3 sử dụng số lưới tối thiểu.
    • Nếu chúng ta tiếp tục kéo ra xa thêm chút nữa và vào phần Culled thì lúc này nhân vật của chúng ta sẽ bị ẩn và không được render.
    • Thiết lập LOD khuyên dùng: Không có thông số nào là thông số bạn phải áp dụng. Hãy thử với game của mình và tính toán về mục tiêu đồ họa mà game hướng tới để điều chỉnh. Như game sử dụng trong bài viết này được sử dụng LOD với các thông số như sau:

  • Điều chỉnh camera:
    • Frustum Culling là một kỹ thuật tối ưu hóa trong Unity và các game engine khác giúp cải thiện hiệu suất bằng cách không render các đối tượng nằm ngoài tầm nhìn của camera. Điều này giúp giảm đáng kể khối lượng công việc mà GPU phải xử lý, vì nó chỉ render các đối tượng mà người chơi có thể nhìn thấy trong view frustum của camera. Để thực hiện điều này, bạn cần tính toán kỹ về thuộc tính Field of View trong Camera cũng như 2 thuộc tính Near và Far để giới hạn những gì sẽ xuất hiện trong camera
    • Occlusion Culling cũng là 1 lựa chọn rất tốt trong Camera giúp loại bỏ những đối tượng không nhìn thấy, bạn không muốn nó xuất hiện hoặc nằm ngoài góc nhìn của camera. 
Trong hình, Minimap camera chỉ hiển thị các đối tượng có lớp Minimap

Tối ưu hóa Textures

Textures (kết cấu) cũng là yếu tố ảnh hưởng lớn đến hiệu suất game. Những chiến lược sau sẽ giúp bạn tối ưu hóa textures một cách hiệu quả:

  • Giảm kích thước textures: Kích thước lớn hơn thường đòi hỏi nhiều bộ nhớ hơn và làm giảm hiệu suất. Unity cho phép điều chỉnh độ phân giải của textures tùy thuộc vào mục tiêu của thiết bị (PC, console, mobile).
  • Sử dụng Power of Two (POT) Textures là các texture có kích thước chiều dài và chiều rộng là số mũ của 2, chẳng hạn như 16, 32, 64, 128, 256, 512, 1024, 2048… Những kích thước này được gọi là Power of Two (POT). Đồ họa và phần cứng thường xử lý tốt các texture với kích thước POT hơn vì các bộ xử lý đồ họa (GPU) được thiết kế để làm việc tối ưu với các kích thước này. 

  • Mipmaps giống như LOD nhưng sử dụng với texture, mipmap là một chuỗi các bản sao của texture, mỗi bản có độ phân giải thấp hơn bản gốc. Khi camera di chuyển ra xa một đối tượng trong cảnh, Unity có thể sử dụng các phiên bản mipmap với độ phân giải thấp hơn để render đối tượng đó, từ đó tiết kiệm tài nguyên và tăng hiệu suất render. 

  • Texture Atlasing: Kỹ thuật này kết hợp nhiều textures nhỏ thành một bản đồ lớn, giảm thiểu số lần chuyển đổi vật liệu và giúp tăng tốc độ render. Bạn có thể sử dụng các công cụ như Blender hay Maya để kiết xuất atlas cho model trước khi sử dụng nó trong Unity.

  • Sử dụng Compress Textures: Compress Textures là một kỹ thuật rất quan trọng trong việc tối ưu hóa game 3D trong Unity. Nó giúp giảm dung lượng của texture trong bộ nhớ mà không ảnh hưởng quá nhiều đến chất lượng hình ảnh, từ đó cải thiện hiệu suất render và giảm thời gian tải game. Việc nén texture cũng giúp tiết kiệm tài nguyên hệ thống, đặc biệt là trên các nền tảng di động với bộ nhớ hạn chế. Các định dạng nén phổ biến trong Unity:
    • DXT (S3TC): Phổ biến trên các nền tảng PC và console, sử dụng nén khối. Đây là một định dạng nén chất lượng cao nhưng không hỗ trợ tốt trên di động.
    • ETC/ETC2: Định dạng nén phổ biến cho Android và OpenGL ES 2.0. Hỗ trợ tốt trên các thiết bị di động và rất tiết kiệm bộ nhớ.
    • PVRTC: Sử dụng cho iOS (Apple) và một số thiết bị Android. Đây là một định dạng nén texture cho phép game chạy trên các thiết bị có bộ nhớ đồ họa hạn chế.
    • ASTC: Hỗ trợ trên nhiều nền tảng, cung cấp nén chất lượng cao với nhiều kích thước khối khác nhau. ASTC là định dạng nén tiên tiến nhất với khả năng cân bằng giữa chất lượng và kích thước file.
Chọn một định dạng nén với game phát triển cho nền tảng PC/Console

Tối ưu hóa game 3D trong Unity đòi hỏi phải xử lý nhiều yếu tố như mô hình, textures, ánh sáng, và việc sử dụng các kỹ thuật tối ưu hóa như Frustum Culling, Occlusion Culling. Những chiến lược này sẽ giúp cải thiện hiệu suất, giảm tải cho GPU và CPU, từ đó mang lại trải nghiệm mượt mà hơn cho người chơi. Phần tiếp theo sẽ tiếp tục với các phương pháp tối ưu hóa ánh sáng, vật lý, script và các công cụ theo dõi hiệu suất trong Unity.

Giảng viên Nguyễn Viết Lập
Bộ môn Công nghệ thông tin
FPT Polytechnic Hà Nội

Cùng chuyên mục

Đăng Kí học Fpoly 2024

  • Max. file size: 50 MB.
  • Max. file size: 50 MB.
  • Max. file size: 50 MB.