Unity Shader 法线贴图的实现

这里有一个细节,关于法线贴图是有两个不同的空间的,如下:

  切线空间:法线贴图颜色为偏蓝色

  模型空间:法线贴图颜色为五颜六色

因此根据不同的空间变换位置方便一致计算。

  1 // 法线贴图映射的编写+透明
  2 Shader "TMoon/05-NormalMapAndAlpha" {
  3     Properties{
  4         _Color("Color",Color) = (1,1,1,1)
  5         _MainTex("Main Tex",2D) = "white"{}
  6         _NormalMap("Normal Map",2D) = "bump"{} //bump默认值的意思:若没有法线贴图,则使用顶点自带的
  7         _BumpScale("Bump Scale",Float) = 1
  8         _AlphaScale("Alpha Scale",Float) = 1
  9     }
 10 
 11     SubShader{
 12 
 13         Tags{ "Queue" = "Transparent" "IngnoreProjector" = "True" "RenderType" = "Transparent" }
 14         
 15         Pass{
 16         
 17             Tags {"LightMode" = "ForwardBase"}
 18 
 19             ZWrite Off
 20             Blend SrcAlpha OneMinusSrcAlpha
 21 
 22             CGPROGRAM
 23 
 24             #include "Lighting.cginc"
 25 
 26             #pragma vertex vert
 27             #pragma fragment frag
 28 
 29             fixed4 _Color;
 30             sampler2D _MainTex;
 31             float4 _MainTex_ST;
 32             sampler2D _NormalMap;
 33             float4 _NormalMap_ST;
 34             float _BumpScale;
 35             float _AlphaScale;
 36 
 37             // application to vertex
 38             // 由应用程序传递给顶点函数
 39             struct a2v {
 40                 float4 vertex:POSITION;
 41                 float3 normal:NORMAL; // 切线空间的确定是通过(存储模型里的)法线和(存储模型里的)切线确定的,所以需要模型的法线
 42                 float4 texcoord:TEXCOORD0; // 模型的纹理坐标
 43                 float4 tangent:TANGENT;// 模型空间的切线
 44             };
 45 
 46             // vertex to fragment
 47             // 由顶点函数传递给片元函数
 48             struct v2f {
 49                 float4 svPos:SV_POSITION;
 50                 float4 uv:TEXCOORD0; // uv.xy 存储MainTex的纹理坐标,uv.zw 存储法线贴图的纹理坐标
 51                 float3 lightDir : TEXCOORD1; // 切线空间下平行光的方向
 52             };
 53 
 54             v2f vert(a2v v) {
 55                 v2f f;
 56 
 57                 f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
 58 
 59                 // 将MainTex纹理坐标赋值给v2f.uv.xy并赋值面板贴图的旋转缩放
 60                 f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
 61                 // 将法线贴图纹理坐标赋值给v2f.uv.zw并赋值面板贴图的旋转缩放
 62                 f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
 63 
 64                 // 调用这个宏之后,会得到一个矩阵 rotation
 65                 // 这个矩阵用来把模型空间下的方向转换成切线空间下
 66                 TANGENT_SPACE_ROTATION;
 67 
 68                 //ObjSpaceLightDir(v.vertex) 得到模型空间下的平行光方向
 69                 f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex));
 70                     
 71                 return f;
 72             }
 73 
 74             float4 frag(v2f f) : SV_Target{
 75 
 76                 // tex2D 根据法线贴图的纹理坐标获取颜色值
 77                 fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
 78 
 79                 // 切线空间下的法线
 80                 fixed3 tangentNormal = UnpackNormal(normalColor);
 81                 tangentNormal.xy = tangentNormal.xy * _BumpScale;
 82                 tangentNormal = normalize(tangentNormal);
 83 
 84                 fixed3 lightDir = normalize(f.lightDir);
 85 
 86                 // tex2D 根据MainTex贴图的纹理坐标获取颜色值
 87                 fixed3 texColor = tex2D(_MainTex,f.uv.xy) * _Color.rgb;
 88 
 89                 // 为漫反射混合上每个像素点的纹理颜色
 90                 fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal, lightDir), 0);
 91 
 92                 return fixed4(diffuse, _AlphaScale);
 93             }
 94 
 95             ENDCG
 96         }
 97     }
 98 
 99     Fallback "VertexLit"
100 }

 

posted on 2017-05-23 17:36  爱裸奔的小亮亮  阅读(2428)  评论(0编辑  收藏  举报

导航