Rendering Path trong Unity: Deferred Shading hay Forward Rendering?
Phuongne, Th3 11, 2020
Lighting
Người xưa cho rằng “Lights are expensive”, điều này đúng, và chính điều này tạo nên sự khác biệt giữa các loại Rendering Path trong Unity, thông thường Deferred Shading sẽ hỗ trợ những dòng máy cấu hình cao như high-end pc, và Foward Rendering sẽ hỗ trợ mobile tốt hơn
“Vậy tại sao lại dựa vào lightings để phân biệt 2 phương pháp render này?”
Trong Unity, một light sẽ render các objects theo 3 kiểu: per-pixel (từng pixel một), per-vertex (từng vertex một) và Spherical Harmonics (SH), theo đó, per-pixel light ngốn performance nhất, tiếp đó là per-vertex,…
Ở 2 khối low-poly trên, per-pixel làm khá tốt phần ánh sáng khi chỉ có rất ít đỉnh, trong khi per-vertex ánh sáng lại có vẻ thô hơn. Trong per-vertex lighting, mỗi vertex sẽ được tính toán một cách riêng biệt, sau đó các pixels ở giữa các vertices sẽ được tính toán phối màu theo thuật toán,
Về per-pixel lighting, mỗi pixel lại được tính toán riêng biệt mà số lượng pixels lớn hơn rất nhiều so với vertices nên rõ ràng rằng mức độ chi tiết cũng như sự phức tạp cao hơn, tiêu tốn tài nguyên hơn per-vertice.
Điều này tạo nên sự khác biệt giữa Deferred Shading rendering và Forward rendering, vào tab Graphics của Project Settings để chọn.
(Vì mình không thường xuyên làm việc với deferred shading nên bài viết sẽ tập trung hơn vào Forward rendering)
Rendering Paths này nằm trong phần 2, Rendering Objects của quy trình Render trong Unity, mình có nói sơ qua trong bài Render Pipeline trong Unity
Deferred Shading Rendering
Ưu điểm
Deferred Shading rendering cho phép vẽ không giới hạn số lượng lights và đặc biệt là per-pixel lights mà vẫn giữ performance ở một giới hạn hợp lý, trong khi nếu sử dụng nhiều lights ở Forward rendering lại tăng số lượng draw call -> giảm graphics performance.
Sử dụng per-pixel lightings, graphics nhìn rất fancy và đẹp mắt.
Ở Deferred Shading, số lượng DrawCall không phụ thuộc vào số lượng lights mà phụ thuộc vào số lượng objects, objects càng nhiều Draw Call càng tăng. Trong khi đó số lượng DrawCall ở Foward Rendering lại phụ thuộc vào cả số lượng lights và số lượng objects, đồng nghĩa thêm một lights sẽ x2 DrawCall cho Objets (chưa tính Shadows, Skybox,…)
(xem ví dụ ở nguồn bài viết – source: catlikecoding)
Nhược điểm
- Deferred Shading không hỗ trợ anti-aliasing (khử răng cưa).
- Không xử lý các vật thể bán trong suốt (alpha < 1) hay semi-transparent GameObjects.
- Không hỗ trợ flag (cờ) Receive Shadows ở component MeshRenderer.
- Giới hạn hỗ trợ về culling masks.
- Ngốn performance nên không sử dụng trên các thiết bị low-end hay mobiles.
Yêu cầu
Các object với shaders không hỗ trợ Deferred shading sẽ sử dụng Forward rendering.
Theo Unity Documents, Deferred Shading yêu cầu card đồ họa có chức năng Multiple Render Targets (MRT) – một chức năng vẽ nhiều images cùng một lúc theo hình minh họa bên dưới. Yêu cầu về Shader Model 3.0 hoặc cao hơn, hỗ trợ vẽ depth texture run-time.
Thông thường, các card đồ họa máy tính cách đây 10-15 năm cũng đã hỗ trợ các chức năng này.
Còn về mobile devices, “chỉ yêu cầu thiết bị chạy OpenGL ES 3.0“, tuy nhiên best practice hiện nay vẫn là tuyệt đối không sử dụng deferred shading trên các mobile games.
Foward Rendering
Foward Rendering khá là quen thuộc đối với các bạn lập trình game mobile (mình) và mặc định built-in rendering path khi tạo một project trên Unity cũng là Foward Rendering
Vì ưu điểm của forward rendering path phần lớn là nhược điểm của deferred shading nên ta không nhắc lại mục này nữa
Khuyết điểm
- Tăng Draw Call nhanh hơn khi sử dụng nhiều lightings
- Graphics không được hoa mỹ và realistic như Deferred Shading
Các Lights trong Forward Rendering
Như đã giới thiệu ở trên, lights trong forward rendering chia làm các loại bao gồm: ver-pixel light, ver-vertex light và spherical harmonics (SH) light, trong đó SH light là light có performance tốt nhất.
Trong Forward Rendering, một vài lights sáng nhất sẽ được mặc định đặt là ver-pixel light, cho phép tối đa 4 point lights chiếu sáng theo kiểu per-vertex, các lights còn lại được tính theo Spherical Harmonics (SH).
Đây là một ví dụ mình trích ra từ Unity3D Documents:
Bối cảnh: tất cả các lights đều có cùng color (màu), intensity (độ sáng), Render Mode là Auto, Pixel Light Count trong Quality là 4.
Theo lý thuyết, các lights sáng nhất sẽ tính toán và render object trên ví dụ theo per-pixel, cho phép tối đa 4 per-vertex lights, số còn lại lại sẽ là SH lights.
Như vậy, A -> D là 4 lights sáng nhất nên sẽ render object trên theo per-pixel, 4 lights tiếp theo (D -> G) sẽ là per-vertex light, còn lại 2 lights G và H là SH lights
“Tại sao 4 lights sáng nhất lại là per-pixel light mà không phải 1 2 3… lights sáng nhất?”
Trong phần bối cảnh mình có đề cập tới Pixel Light Count trong Quality tab (Edit -> Project Setting -> Quality) bằng 4, như vậy sẽ lấy tối đa 4 per-pixel lights
“Chỗ chỉnh sửa Render Mode cho các lights này ở đâu vậy?”
Chúng ta vào component Light xem phần Render Mode, có 3 cờ (flags): Important, Not Important và Auto:
- Not Important: Light với setting này sẽ thuộc loại per-vertex hoặc SH.
- Important: render theo per-pixel.
- Auto: đây là cờ mặc định của Light component, Light sẽ được xác định theo độ ưu tiên về độ sáng (brightness) và khoảng cách (distance) tới object.
“Nếu ở ví dụ ban nãy Render Mode không phải là Auto mà là Important hoặc Not Important thì sao?”
Vì mình không thấy nhiều tài liệu nên đã làm một vài thử nghiệm trên phiên bản 2019.3.0f6:
Các Lights có renderMode là Important và Not Important không phụ thuộc vào thuộc tính Pixel Light Count Count (PLC) trong Quality tab mà ngược lại
- Important-light luôn là per-pixel light và Not-important-light luôn là per-vertex (hoặc SH) light bất kể PLC = 0 hay = n.
- Mặc dù Important (hoặc Not-important) light không bị ảnh hưởng bởi PLC nhưng PLC lại bị ảnh hưởng bởi 2 kiểu lights đó
Ví dụ có 3 important lights và PLC = từ 0 -> 3 thì các auto-light (renderMode = Auto) còn lại đều không phải là per-pixel.
Disclaimer
Bài viết được đăng vào 2020, chỉ có giá trị tham khảo các bạn nhé
Lời kết và nguồn tham khảo
https://blog.theknightsofunity.com/forward-vs-deferred-rendering-paths/
https://catlikecoding.com/unity/tutorials/rendering/part-13/
https://docs.unity3d.com/Manual/RenderTech-ForwardRendering.html
https://docs.unity3d.com/Manual/RenderTech-DeferredShading.html
All rights reserved