12/08/2018, 11:56

Shader code Unity

Trong Unity 3D cũng như bất kỳ engine làm game nào khác, shader là 1 yếu tố vô cùng quan trọng với model để hiệu ứng hình ảnh trong game trở nên sống động, cuốn hút người chơi. Với các game lớn hiện nay như Swticher, Batman, ... shader trong game là cả 1 vấn đề cực lớn. Ở bài này, chúng ta sẽ tìm ...

Trong Unity 3D cũng như bất kỳ engine làm game nào khác, shader là 1 yếu tố vô cùng quan trọng với model để hiệu ứng hình ảnh trong game trở nên sống động, cuốn hút người chơi. Với các game lớn hiện nay như Swticher, Batman, ... shader trong game là cả 1 vấn đề cực lớn. Ở bài này, chúng ta sẽ tìm hiểu cơ bản về cách code shader trong unity, và làm 1 ví dụ nhỏ về 1 phần trong shader: surface shader.

  1. Shader trong unity

    Có 3 cách để code shader trong unity:

  • surface shaders

  • vertex and fragment shaders

  • ixed function shaders

    Không liên quan bạn dùng cách nào, shader code được viết bởi ngôn ngữ ShaderLab, dùng để tổ chức cấu trúc shader. Với cấu trúc cơ bản:

  Shader "MyShader" {
        Properties {
            _MyTexture ("My Texture", 2D) = "white" { }
            // other properties like colors or vectors go here as well
        }
        SubShader {
            // here goes the 'meat' of your
            // - surface shader or
            // - vertex and program shader or
            // - fixed function shader
        }
        SubShader {
            // here goes a simpler version of the SubShader
            // above than can run on older graphics cards
        }
  }
  1. Cú pháp của ShaderLab

    Tất cả file shader trong Unity đều được viết băng ShaderLab. Ở trong file, một cú pháp nested-braces dùng để khai báo các giá trị xác định shader, ví dụ các thuộc tính của shader sẽ được hiển thị trên material ínpector, các loại phần cứng cần, chế độ blending được gọi,... Và thực sự "shader code" viết trên 1 đoạn CGPROGRAM trong cùng shader file. Và đoạn CGPROGRAM viết trên ngôn ngữ shading chung: HLSL/Cg. Cú pháp:

    Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] }
Properties: shader có thể có 1 list các thuộc tính. Mỗi thuộc tính xác định cách thể hiện của shader trong material inspector trong unity. properties có thể là màu, texture, ...

Subshader và fallback: mỗi shader gồm 1 list các sub-shaders. Yêu cầu ít nhất 1. Khi load shader, Unity sẽ đi qua hết list sub-shader, và chọn cái đầu tiên được hỗ trợ bởi uer's machine. nếu không có subshader được hỗ trợ, Unity sẽ dùng tới fallback shader.
Cạc màn hình khác nhau sẽ có các khả năng khác nhau. Nó sẽ tạo nên các vấn đề muôn thưở cho developer. Bạn muốn game nhìn tuyệt vời trong phần cứng mới nhất, nhưng không muốn nó chỉ có thể chạy trên 3% của các phần cứng hiện hành. Đây là lúc subshaders gọi đến. Tạo ra 1 subshaders với tất cả hiệu ứng đồ hoạ lung linh nhất bạn có thể ngĩ ra, sau đó thêm các subshaders vào trong cạc cũ. Các subshader có thể implement các hiệu ứng bạn muốn với một cách chậm hơn, hoặc họ có thể chọn không hiển thị một số chi tiết.
Một ví dụ về shaders:
    // colored vertex lighting
Shader "Simple colored lighting"
{
    // a single color property
        Properties {
            _Color ("Main Color", Color) = (1,.5,.5,1)
        }
        // define one subshader
        SubShader
        {
            // a single pass in our subshader
            Pass
            {
                // use fixed function per-vertex lighting
                Material
                {
                    Diffuse [_Color]
                }
                Lighting On
            }
        }
}
Ở đây shader xác định một thuộc tính màu sắc: Color sẽ được hiển thị trên material inspector như Main Color với giá trị mặc định (1, 0.5, 0.5, 1). Sau đó 1 subshader được xác định. Subshader bao gồm 1 Pass, với tuỳ chọn Lighting On và material mặc đinh kiểu Diffuse.
  1. Ví dụ về surface shader

    Chúng ta sẽ bắt đầu với một shader đơn giản, và xây dựng trên đó. Đây là một shader với màu trắng, và lighting model kiểu diffuse.

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"
  }

Screen Shot 2015-09-24 at 9.38.21 AM.png Sẽ rất nhàm chán khi đối tương chỉ có màu trắng, chung ta sẽ add thêm texture:

Shader "Example/Diffuse Texture" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Screen Shot 2015-09-24 at 9.38.38 AM.png

Chúng ta có thể sử dụng hàm "vertex modifier" để điều chỉnh dữ liệu các đỉnh trên vertex shader. Nó có thể sử dụng trong animation, extrusion, ... Surface shader có dùng vertex:functionName để làm việc đó.

Đây là một shader chuyển các đỉnh dọc theo vị trí định sẵn của chúng trên vật liệu:

Shader "Example/Normal Extrusion" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Amount ("Extrusion Amount", Range(-1,1)) = 0.5
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert vertex:vert
      struct Input {
          float2 uv_MainTex;
      };
      float _Amount;
      void vert (inout appdata_full v) {
          v.vertex.xyz += v.normal * _Amount;
      }
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Và tạo ra một binh sĩ rất béo. Screen Shot 2015-09-25 at 1.45.54 PM.png

0