1. 程式人生 > >一個示例性的Unity Shader例子

一個示例性的Unity Shader例子

         
Shader "Custom/NormSpecular" {
 Properties {
  _MainTex ("Base (RGB)", 2D) = "white" {}
  _Bump ("Bump", 2D) = "bump" {}
  _Specular ("Specular", Range(1.0, 500.0)) = 250.0
 }
 SubShader {
  Tags { "RenderType"="Opaque" }
  LOD 200
   
  Pass {
   Tags { "LightMode" = "ForwardBase" }
     
   CGPROGRAM
     
   #pragma vertex vert
   #pragma fragment frag
   #pragma multi_compile_fwdbase
      
   #include "UnityCG.cginc"
   #include "Lighting.cginc"
   #include "AutoLight.cginc"
     
   uniform float4x4 _LightMatrix0; // 引入光矩陣
   sampler2D _MainTex;
   sampler2D _Bump;
   float _Specular;
   float _Gloss;
   float4 _MainTex_ST;
     
   struct a2v {
    float4 vertex : POSITION;  // 輸入的模型頂點資訊
    fixed3 normal : NORMAL;   // 輸入的法線資訊
    fixed4 texcoord : TEXCOORD0; // 輸入的座標紋理集
    fixed4 tangent : TANGENT;  // 切線資訊
   };
     
   struct v2f {
    float4 pos : POSITION; // 輸出的頂點資訊
    fixed2 uv : TEXCOORD0; // 輸出的UV資訊
    fixed3 lightDir: TEXCOORD1; // 輸出的光照方向
    fixed3 viewDir : TEXCOORD2; // 輸出的攝像機方向
    fixed3 _LightCoord : TEXCOORD3;  // 光照座標
    fixed4 _ShadowCoord : TEXCOORD4; // 陰影座標
    fixed3 vertexLighting:TEXCOORDS5;//頂點光照強度
   };
     
   v2f vert(a2v v) {
    v2f o;
    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
       
    // 建立一個正切空間的旋轉矩陣,TANGENT_SPACE_ROTATION由下面兩行組成
    //TANGENT_SPACE_ROTATION;
    float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
    float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal );
    
    // 將頂點的光方向,轉到切線空間
    // 該頂點在物件座標中的光方向向量,乘以切線空間旋轉矩陣
    o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
    // 該頂點在攝像機座標中的方向向量,乘以切線空間旋轉矩陣
    o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex));
       
    // 將照明資訊給畫素著色器,應該是用於下面片段中光衰弱atten的計算
      // TRANSFER_VERTEX_TO_FRAGMENT(o); // 由下面兩行組成
    // 頂點轉到世界座標,再轉到光座標
    o._LightCoord = mul(_LightMatrix0, mul(_Object2World, v.vertex)).xyz;
    o._ShadowCoord = mul(unity_World2Shadow[0], mul(_Object2World, v.vertex));
    o.vertexLighting = fixed3(0.0,0.0,0.0);
    o.vertexLighting = Shade4PointLights(unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0,
    unity_LightColor[0].rgb,unity_LightColor[1].rgb,unity_LightColor[2].rgb,unity_LightColor[3].rgb,
    unity_4LightAtten0,mul(_Object2World,v.vertex),normalize(mul(float4(v.normal,0.0),_World2Object).xyz));
    return o;
   }
     
   fixed4 frag(v2f i) : COLOR {
    // 對主紋理進行取樣
    fixed4 texColor = tex2D(_MainTex, i.uv);
    // 對法線圖進行取樣
    fixed3 norm = UnpackNormal(tex2D(_Bump, i.uv));
    // 光衰弱,臥槽,裡面封裝了比較深,暫時看不進去,就不拆開了
    fixed atten = LIGHT_ATTENUATION(i);
    // 求漫反射
    // 公式:漫反射色 = 光顏色*N,L的餘弦值(取大於0的),所以夾角越小亮度越小
    fixed3 Diff = dot (normalize(norm),  normalize(i.lightDir));//半形向量
    fixed3 HalfVector = normalize(i.lightDir + i.viewDir);
    fixed NdotH = max(0,dot(norm,HalfVector));
    fixed specularpower = pow(NdotH,_Specular)*sign(Diff);
    Diff = saturate(Diff);
    // 計算反射高光
    // 公式:反射高光 = 光顏色 * 【(反射光向量,攝像機方向向量)的餘弦值】的【高光指數_Specular】次方 * 光澤度
    fixed4 fragColor;
    fragColor.rgb = texColor.rgb*(((Diff+specularpower)*_LightColor0.rgb)*(atten*Diff*2)+i.vertexLighting);
    fragColor.a = texColor.a;
    return fragColor;
    }
    ENDCG
  }
 }
 FallBack "Diffuse"
}


Unity5.2.3下編譯通過