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 }