一个示例性的Unity Shader例子

7 篇文章 0 订阅
5 篇文章 0 订阅

        前言:一个简单的Unity使用顶点片段着色器的镜面反射的例子,虽然很简单却很实用----在使用多个pass时,移植性比表面着色器的移植性要好。

         

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下编译通过

           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值