Đăng ký
Cộng đồng phát triển game Việt - kết nối đam mê !

 shader là gì


shader là một chương trình đặc biệt được viết ra để chạy trên GPU tức bộ xử lý đồ hoạ . 


Trên trang chủ của Unity định nghĩa shader là những script nhỏ gồm các phép toán  và thuật toán để tính toán màu sắc cho mỗi điểm ảnh render lên , dựa trên ánh sáng và cấu hình  vật liệu .


Trong unity có sự liên hệ mật thiết giữa texture, material và  shader :


- materials (vật liệu) biểu hiện cho một bề mặt vật liệu nó bao gồm những tham chiếu tới những texture (hình ảnh ) được sử dụng , thông tin về tiling , color và nhiều thứ nữa . Các tuỳ chọn có sẵn cho một loại vật liệu phụ thuộc vào shader mà vật liệu đó sử dụng .


- Texture là những hình ảnh bitmap . Một material có thể chứa các tham chiếu đến các texture , để shader của material có thể sử dụng texture trong khi tính toán màu sắc bề mặt của đối tượng . Ngoài màu sắc cơ bản của bề mặt một đối tượng , texture có thể đại diện cho nhiều khía cạnh khác của bề mặt vật liệu như độ phản xạ hoặc độ gồ ghề của nó .


Nhìn biểu đồ dưới đây bạn sẽ thấy ba thực thể đóng vai trò render hình ảnh trong Unity 


 


Ta có thể thấy shader là thực thể cuối cùng trong việc render hình ảnh ra màn hình 


 


Một mô hình 3D về cơ bản gồm một tập các toạ độ gọi là các đỉnh (vertices). Chúng được kết nối với nhau tạo nên các tam giác (triangles). Mỗi đỉnh có thể chứa vài thông tin khác như màu sắc , hướng nó gọi là đỉnh bình thường (normal) và một số toạ độ bản đồ texture kết cấu vào nó (gọi là dữ liệu UV) .


 


Mô hình không thể hiển thị nếu không có một vật liệu . Vật liệu được bao bọc , chứa một shader và các giá trịn cho thuộc tính của nó . Do đó các vật liệu khác nhau có thể chia sẻ chung shader với những bộ dữ liệu khác nhau .


Cấu trúc của một shader


Unity hỗ trợ hai loại shader là : suface shader và fragment and vertex shaders . Kiểu thứ ba là fixed function shader nhưng bây giờ nó đã lỗi thời và không còn hay được sử dụng nữa . Bất kỳ kiểu gì thì nó đề có một cấu trúc như sau :


 



bạn có thể có nhiều phần SubShader . Chúng chứa những hướng dẫn thực tế cho GPU . Unity3D sẽ cố gắng thực hiện theo đúng thứ tự cho đến khi nó tìm thấy một trong số đó tương ứng với card đồ hoạ của bạn . Điều này rất hứu ích khi code cho các nền tảng khác nhau, kể từ khi bạn có thể hợp với các phiên bản khác nhau của cùng một shader trong một tập tin duy nhất .


Các thuộc tính


Các thuộc tính của shader  là bằng cách nào đó tương đương với các trường public trong một script C#; chúng sẽ xuất hiện trong inspector của material của bạn, bạn có thể tinh chỉnh chúng. Không giống như những gì xảy ra với một script, material là assets: thay đổi các thuộc tính của một vật trong khi game đang chạy trong editor là vĩnh viễn. Ngay cả sau khi ngừng các trò chơi, bạn sẽ thấy những thay đổi bạn đã thực hiện vẫn còn trong material của bạn.


 


Đoạn code sau đây bao gồm các định nghĩa của tất cả các loại cơ bản của material mà bạn có thể có trong một Shader:



Kiểu 2D  được sử dụng trong dòng 3-4, cho thấy các thông số của texture. Chúng có thể được khởi tạo với màu trắng, đen hoặc xám. Bạn cũng có thể sử dụng bump để cho biết rằng các texture sẽ được sử dụng như là một normal map. Trong trường hợp này, nó sẽ tự động khởi tạo các màu # 808080, được sử dụng để đại diện không có bump ở tất cả. Vectors và màu sắc luôn có bốn yếu tố (XYZW và RGBA, tương ứng).


Những hình ảnh dưới đây cho thấy làm thế nào những thành phần xuất hiện trong inspector, một khi shader được gắn vào một material.


 



 


Thật không may, điều này là không đủ để sử dụng các Properties của chúng ta. Properties section  trong thực tế được sử dụng bởi Unity3D để cung cấp cho truy cập từ inspector cho các biến ẩn trong một Shader. Các biến này vẫn cần phải được xác định trong body thực tế của shader, nó được chứa trong phần SubShader.



kiểu đã sử dụng cho texture là sampler2D. Vectors là float4 và màu sắc nói chung là half4 mà sử dụng 32 và 16 bit, tương ứng. Các ngôn ngữ dùng để viết shaders, Cg / HLSL, rất mô phạm: tên của các tham số phải phù hợp chính xác với một định nghĩa trước.  Bạn sẽ không nhận được bất kỳ lỗi cho khai báo _MyRange như half, thay vì float. Một cái gì đó khá khó hiểu là một thực tế rằng nếu bạn có thể xác định một loại tài sản của Vector, được liên kết với một biến float2; hai giá trị tăng thêm sẽ được bỏ qua bởi Unity3D.


Thứ tự render


Như đã đề cập, phần SubShader chứa mã thực tế của shader, viết bằng Cg / HLSL gần giống với C.  nội dung của một Shader được thực thi cho mỗi điểm ảnh của hình ảnh của bạn; hiệu suất ở đây là rất quan trọng. Do cấu trúc của GPU, có một giới hạn về số lượng các hướng dẫn mà bạn có thể thực hiện trong một Shader. Có thể tránh điều này bằng cách chia các tính toán trong một vài đường chuyền khác nhau, nhưng điều này sẽ không được đề cập trong hướng dẫn này.


 


Nội dung của một Shader, thường trông như thế này:


 



 


Dòng 8-11 chứa code Cg bạn viết trong đó ; phần được đánh dấu bằng đoạn CGPROGRAM và END để viết code.


 


Dòng 3,  nói với chúng ta  các khái niệm về Tags. Tags là một cách để nói với Unity3D các properties của shader chúng ta đang viết. Ví dụ, thứ tự mà nó phải được render (Queue) và làm thế nào nó được render (RenderType).


 


Khi dựng các triangles, GPU thường sắp xếp chúng theo khoảng cách từ camera, vì vậy mà những cái ở gần sẽ được vẽ ra đầu tiên. Đây là đủ để cho những hình có thể nhìn thấy , nhưng nó thường không thành công với đối tượng trong suốt. Đây là lý do tại sao Unity3D cho phép xác định các thẻ Queue cho phép kiểm soát về trình tự render của từng material. Queue chấp nhận số nguyên dương ( càng nhỏ càng được vẽ trước); label ghi nhớ cũng có thể được sử dụng:


 


- Backgrouond (1000): được sử dụng cho hình nền và các skybox


- Geometry (2000): nhãn mặc định sử dụng cho hầu hết các vật thể rắn,


- Transparent (3000): sử dụng cho vật liệu có tính minh bạch, kính , lửa, praticles và nước;


- Overlay (4000): được sử dụng cho các hiệu ứng như pháo sáng ống kính, các yếu tố GUI và các văn bản


 


Unity3D cũng cho phép xác định thứ tự tương đối, như Background + 2, có nghĩa là giá trị hàng đợi là 1002. với Queue có thể tạo ra những tình huống khó chịu khi mà một đối tượng luôn được vẽ ra, ngay cả khi nó phải được bao phủ bởi các mô hình khác.


 


ZTEST


Điều quan trọng cần nhớ là, có một đối tượng từ trong suốt không nhất thiết phải luôn luôn xuất hiện trên một đối tượng từ Geometry. GPU, theo mặc định, thực hiện một thử nghiệm được gọi ZTEST mà dừng pixel ẩn được vẽ ra. Để làm việc đó, nó sử dụng một bộ đệm thêm với cùng kích thước của màn hình mà nó vẽ lên. Mỗi pixel chứa chiều sâu (khoảng cách từ máy ảnh) của đối tượng được vẽ theo pixel. Nếu chúng ta muốn viết một pixel mà là xa hơn độ sâu hiện nay, các điểm ảnh được loại bỏ. ZTEST tiêu huỷ các điểm ảnh được ẩn bằng các đối tượng khác bất kể thứ tự mà chúng được vẽ lên màn hình.


 


Surface versus vertex và fragment


Phần cuối cùng cần phải được quan tâm là mã code của các shader. Trước khi làm điều này, ta sẽ phải quyết định loại shader để sử dụng. Phần này sẽ cung cấp cho một cái nhìn thoáng qua về cách shader trông như thế nào, nhưng nó sẽ không thực sự giải thích cho chúng. Cả hai Surface versus vertex và fragment shader sẽ được đề trong các phần tiếp theo của bài này.


 


surface shader


Bất cứ khi nào các material mà bạn muốn mô phỏng  bị ảnh hưởng bởi ánh sáng một cách thực tế, rất có thể bạn sẽ cần một surface Shader. surface shaders  ẩn các tính toán như thế nào ánh sáng được phản xạ và cho phép xác định các đặc tính "trực quan" như phản xạ, các phản xạ và như vậy trong một hàm gọi là surf. Những giá trị này sau đó thêm vào một lighting model đó sẽ ra các giá trị RGB cuối cùng cho mỗi pixel. Ngoài ra, bạn cũng có thể viết lighting model của riêng của bạn, nhưng điều này chỉ cần thiết cho các hiệu ứng rất cao.


 


Mã Cg của một surface Shader  điển hình trông như thế này:


 




 


Dòng 5 đầu vào là một texture, sau đó được thiết lập như là property Albedo của material trong dòng 12. Các shader sử dụng một lighting model  Lambertian (dòng 3), đó là một cách rất đặc trưng của mô hình và ta thấy  ánh sáng phản chiếu vào một đối tượng như thế nào. Shaders mà chỉ sử dụng property albedo phản chiếu thường được gọi là diffuse (khuếch tán).


 


vertex và fragment shader


Vertex và fragment shaders làm việc gần với cách GPU render triangles, và không có tích hợp trong khái niệm của ánh sáng . geometry của mô hình của bạn lần đầu tiên thông qua  một hàm gọi là vert mà có thể thay đổi các đỉnh của nó. Sau đó, triangles được chuyển qua một hàm gọi là frag nơi quyết định màu RGB cho mỗi điểm ảnh. Chúng rất có ích cho các hiệu ứng 2D, xử lý sau và các hiệu ứng 3D đặc biệt là hiệu ứng quá phức tạp so với surface shader.


 


Các vertex và fragment shader chỉ đơn giản là làm cho đối tượng thống nhất màu đỏ, không có ánh sáng:


 




 


Dòng 15-17 chuyển các đỉnh từ không gian 3D bản địa  đến vị trí 2D cuối cùng trên màn hình. Unity3D giới thiệu UNITY_MATRIX_MVP để ẩn toán học đằng sau nó. Sau này, dòng 22 sẽ cho ra màu đỏ cho mỗi pixel. Chỉ cần nhớ rằng phần Cg của Vertex và fragment shaders cần phải được kèm theo trong một phần Pass. Đây không phải là trường hợp cho surface shaders đơn giản, mà sẽ làm việc có hay không có nó.


 


Phần kết luận


Bài này giới thiệu hai loại shader trong Unity và giải thích cách sử dụng chúng . Ở bài tiếp theo tôi sẽ  giải thích làm thế nào để thực hiện chúng một cách chi tiết. 


Việc học shader trong game Unity là quan trọng để game của bạn đẹp hơn vì thế nếu làm Unity nhất định bạn phải biết tới nó .

Captcha Challenge