Phuongne, Th4 13, 2020
I. Mở đầu
Khi làm quen với Unity, chúng ta thường không đụng gì đến shader cũng như cách mà GPU render vật thể, vì vậy shader có vẻ gì đó khá là bí ẩn trong mắt của developer.
Tuy nhiên có nhiểu trường hợp đặc biệt, để có các hiệu ứng fancy hay render một vật thể theo ý muốn, chúng ta cần phải sử dụng tới shader khá là nhiều, ví dụ như tạo outline của nhân vật 2D cho Sprite Renderer, hay một số hiệu ứng dưới đây:
II. Shader là gì?
Shader có thể coi là tên gọi chung của loại script được viết ra để chạy trên GPU hay can thiệp vào quá trình vẽ để tạo các vật thể, hiệu ứng đặc biệt.
Unity hỗ trợ 3 loại shader bao gồm: Surface shader, Vertex & Fragment shader và Fixed Function shader, tuy nhiên Fixed Function shader đã trở nên lỗi thời khi chỉ có thể tạo các hiệu ứng đơn giản, không còn phù hợp trong thời đại game hiện nay.
Ngoài shader, chúng ta còn một thuật ngữ gọi là Shaderlab, bất kỳ sử dụng loại shader nào, scripts của chúng đều được gói ở trong shaderlab.
Shaderlab sẽ định nghĩa các thông tin cần biết của một shader như các properties nào được hiện lên inspector để điều chỉnh và debug, loại phần cứng nào sẽ sử dụng hiệu ứng này, nếu loại phần cứng này không hỗ trợ thì sẽ fallback về hiệu ứng nào (đơn giản hơn), blend mode nào được sử dụng,..
Chúng ta sẽ tìm hiểu Shaderlab syntax ở phần sau, vì vậy hiện tại chỉ cần hiểu nó định nghĩa thêm một vài thông tin về cách sử dụng shader này như thế nào.
III. Surface Shader
Nếu bạn muốn một Material đơn giản có khả năng mô phỏng hay tương tác với ánh sáng, để nhanh gọn thì chúng ta sẽ cần tới Surface shader.
Việc tính toán màu sắc, phản xạ ánh sáng sẽ được tính toán bởi Unity và chúng ta chỉ cần điều chỉnh các properties như albedo, normals hay hệ số phản xạ,… sau đó các giá trị này sẽ được đưa vào Lighting Model mô phỏng màu sắc, ánh sáng cho từng pixel mà chúng ta không cần can thiệp.
Nhưng nếu muốn, chúng ta vẫn hoàn toàn có thể custom lại một Lighting Model, các bạn có thể xem thêm ở Custom lighting models in Surface Shaders
Chúng ta sẽ xem qua một ví dụ để hiểu hơn một chút cách surface shader hoạt động
Shader "Example/Diffuse Simple" { SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float4 color : COLOR; }; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = 1; } ENDCG } Fallback "Diffuse"
}
Hiện tại chúng ta chỉ quan tâm 2 dòng ở trong section CGPROGRAM:
- #pragma surface surf Lambert: sử dụng Lambert lighting model, chúng ta chỉ việc gọi tên lighting model, unity sẽ tự xử lý lighting.
- o.Albedo = 1: vì không truyền vào texture cho input, chúng ta có thể chọn màu cho model bằng thuộc tính albedo, ở ví dụ trên sẽ là màu trắng (1 = white = rgb(1,1,1))
IV. Vertex & Fragment Shader
Loại shader này làm việc như gần như là cách mà GPU vẽ một vật thể vậy, không có hỗ trợ thêm lighting như surface shader, tuy nhiên điều này cũng cho ta khả năng custom cao hơn, khả năng kiểm soát cũng tốt hơn.
Theo như tên gọi của nó, loại shader này bao gồm 2 phần: vertex và fragment, trong đó phần vertex sẽ làm nhiệm vụ xử lý các đỉnh đầu vào của vật thể bằng hàm vert, sau khi đã xử lý xong, hàm cho ra output có thể là các triangles, uv,… sau đó output sẽ được rasterization (tạo điểm ảnh từ các đỉnh) thành một ma trận pixels, xem hình dưới
Output sau khi đã xử lý của vert được chuyển thành phần input của hàm frag (hàm chính của phần fragment), nhiệm vụ của frag là từ các dữ liệu đầu vào tính toán màu sắc cho từng pixels của vật thể hay nói cách khác output của frag chính là màu sắc.
Hay các bạn muốn biết cách GPU đưa quá trình này vào đâu có thể xem series này Graphic cho Game dev
Claims
Bài viết được đăng vào 2020, chỉ có giá trị tham khảo các bạn nhé