ShaderLab 法线贴图(凹凸材质)

http://www.manew.com/thread-97665-1-1.html



内容说明:
    1. 法线贴图的原理
    2. 法线贴图的unity实现

1. 法线贴图的原理
    1.1 什么是法线贴图?
    每个顶点都有一条法线,三角形内部法线由插值计算得出,颜色则是直接从纹理取数据。法线贴图的基本思想就是像纹理采样一样为法线取值。
    1.2法线纹理
    下图是一张法线的纹理图:
 
  每个纹素的RGB值实际上表示的是XYZ向量:颜色的分量取值范围为0到1,而向量的分量取值范围是-1到1;可以建立从纹素到法线的简单映射:
normal = (2*color)-1
   法线纹理的映射方式和漫反射纹理相似。麻烦之处在于如何将法线从各三角形局部空间(切线空间tangent space,亦称图像空间image space)变换到模型空间(着色计算所采用的空间)。
    1.3切线空间
    大家对矩阵已经十分熟悉了,应该知道定义一个空间需要三个向量。现在Up向量已经有了,即法线:
 
   然后是切线T:垂直于法线的向量。但这样的切线有很多个:
 
这么多切线中该选哪个呢?理论上哪一个都行。但我们必须保持连续一致性,以免衔接处出现瑕疵。Unity已经给我提供好了Tangent。
    定义一组基需要三个向量,因此我们还得计算副切线B。可以使用法线和切线叉乘计算得到。那么切空间就可以表示成如下图这样了。
 
已知T、B、N向量之后,即可得下面这个漂亮的矩阵,完成从切线空间到模型空间的变换:
 
只需对上述矩阵求逆即可得逆变换。这个矩阵(正交阵,即各向量相互正交的矩阵,参见下文“延伸阅读”小节)的逆矩阵恰好也就是其转置矩阵,计算十分简单:
 
2. unity中的实现
   我们看下unity实现的代码:
[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Shader "Custom/NewSurfaceShader" {
     Properties {
                 _MainText( "MainText" ,2D)= "white" {}               
                 _BumpMap( "BumpMap" ,2D)= "white" {}
         }
         SubShader {
                 pass{
                 Tags{ "LightMode" = "ForwardBase" }
                 CGPROGRAM
                 #pragma vertex vert
                 #pragma fragment frag
                 #include "UnityCG.cginc"
 
                 float4 _LightColor0;
                 sampler2D _BumpMap;
                 sampler2D _MainText;
                 struct v2f {
                         float4 pos:SV_POSITION;
                         float2 uv:TEXCOORD0;
                         float3 lightDir:TEXCOORD1;
                 };
 
                 v2f vert (appdata_full v) {
                         v2f o;
                         o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
                         o.uv=v.texcoord.xy;
                         TANGENT_SPACE_ROTATION;
                         o.lightDir= mul(_World2Object, _WorldSpaceLightPos0).xyz; //Direction Light
                         o.lightDir=mul(rotation,o.lightDir);
                         return o;
                 }
                 float4 frag(v2f i):COLOR
                 {
                         float4 c=1;
                         float3 N=UnpackNormal(tex2D(_BumpMap,i.uv));
                         float diff=max(0,dot(N,i.lightDir));
                         c=_LightColor0*diff;
                         c*=tex2D(_MainText,i.uv);
                         return c;
                 }
                 ENDCG
                 }
         }
}

   我们把光照贴图给附上,材质分别给一个平面和一个球看下效果:
 
 
2.3 UnpackNormal函数说明
[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
{
         fixed3 normal;
         normal.xy = packednormal.wy * 2 - 1;
         normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
         return normal;
}
 
inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
         return packednormal.xyz * 2 - 1;
#else
         return UnpackNormalDXT5nm(packednormal);
#endif
}

可以看见不同的压缩格式解析有一定的区别,上面讲解的不是很全面,想了解更多可以自行百度下。
2.4 用Surface Shader来实现下
[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Shader "Custom/SurfaceShader" {
         Properties {
                 _MainTex ( "Base (RGB)" , 2D) = "white" {}
                 _BumpMap ( "Normalmap" , 2D) = "bump" {}
         }
 
         SubShader {
                 Tags { "RenderType" = "Opaque" }
                 LOD 250
 
                 CGPROGRAM
                 #pragma surface surf Lambert noforwardadd
                 sampler2D _MainTex;
                 sampler2D _BumpMap;
                 struct Input {
                         float2 uv_MainTex;
                 };
 
                 void surf (Input IN, inout SurfaceOutput o) {
                         fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
                         o.Albedo = c.rgb;
                         o.Alpha = c.a;
                         o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
                 }
                 ENDCG 
         }
         FallBack Off
}

代码下载地址http://pan.baidu.com/s/1boCvoIz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值