码迷,mamicode.com
首页 > 其他好文 > 详细

NormalMap 法线贴图

时间:2015-10-22 01:32:42      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:

技术分享

法线贴图

  存储法线的一张贴图,法线的 xyz 的值被映射成为对应的 RGB 值。即法线的分量由(-1,1)映射成(0,127)。法线贴图一般呈蓝色,因为大多数朝向 (0,0,1)的法线被映射成为了 (0,0,127)。

切空间(Tangent Space,TBN):纹理空间

  切空间是在某一点所有的切向量组成的线性空间。也就是说,在模型每个顶点中,都存在这样的一个切空间坐标系,以模型顶点为圆心,再加上TBN3个轴(Tangent,Binormal,Normal),N是顶点的法线方向,T、B两个向量是顶点切平面的2个向量,一般T的方向是纹理坐标u的方向,B的方向通过TN叉乘计算得到。而法线贴图就是记录该空间下顶点的法线方向,它不是固定(0,0,1)而是在切空中间中的扰动值。现在,我们要将切空间下的法线值,变换到世界空间,计算光照。

  首先,我们需要计算出切空间到世界空间的变换矩阵。切空间由3个向量定义,Tangent,Binormal,Normal;我们在模型顶点中已知Tangent和Normal的值,那么Binormal可以通过前2个向量的叉乘来取得。

    

1             struct vertexInput{
2                 float4 vertex:POSITION;
3                 float3 normal:NORMAL;
4                 float4 texcoord:TEXCOORD0;
5                 float4 tangent:TANGENT;
6             };

 

    计算世界空间的Normal: o.normalWorld = normalize( mul(float4(v.normal,0.0),_World2Object).xyz); 法线转世界空间不同于顶点,需要解决缩放问题。

    计算世界空间的Tangent: o.tangentWorld = normalize( mul(_Object2World, v.tangent).xyz); 

    计算世界空间的Binormal: o.binormalWorld = normalize( cross(o.normalWorld,o.tangentWorld)*v.tangent.w); 叉乘:右手定则。

   有了这3个切向量,我们就可以定义变换矩阵:

1           float3x3 local2WorldTranspose=float3x3(
2                     i.tangentWorld,
3                     i.binormalWorld,
4                     i.normalWorld
5                 );

  三个向量构建出了的矩阵,而这三个向量分别对应了World Space中的tangent、binormal和normal的方向,这三个方向对应了Tangent Space中的三个坐标轴的方向。这里有一点点难懂。但其实就是一个坐标变换,如果我们想得到从坐标系A转换到坐标系B的一个变换矩阵,我们只需用A中B的三个坐标轴的方向、按X、Y、Z轴的顺序构建一个矩阵即可(这里需要注意是行向量还是列向量,例如OpenGL使用的是列向量)。

  最后将采样的法线纹理通过该转换矩阵,转换到世界坐标,进行光照计算即可。

法线Shader:基础

技术分享

  1. 在属性中声明:

    

        _BumpMap ("Normal Texture", 2D) = "bump" {}        
        _BumpDepth("_Bump Depth",Range(-2,2.0)) = 1

 

  2. Pass中声明变量:

            float4 _BumpMap_ST;
            uniform float _BumpDepth;

  3. 在 Vertex 函数中计算世界空间的TBN:

                o.normalWorld =  normalize( mul(float4(v.normal,0.0),_World2Object).xyz);
                o.tangentWorld =  normalize( mul(_Object2World, v.tangent).xyz);
                o.binormalWorld =  normalize( cross(o.normalWorld,o.tangentWorld)*v.tangent.w);

  4. 在 Fragment 函数中构建切空间到世界空间的转换矩阵:

          float3x3 local2WorldTranspose=float3x3(
                    i.tangentWorld,
                    i.binormalWorld,
                    i.normalWorld
                );

  5. 在 Fragment 函数中采样法线贴图,转换到[-1,1],并转换到世界空间:

                float4 texN  = tex2D(_BumpMap,i.tex.xy*_BumpMap_ST.xy+_BumpMap_ST.zw);
          float3 localCoords = float3(2.0*texN.ag-float2(1.0,1.0),0.0);
		localCoords.z = _BumpDepth;
          float3 normalDirection = normalize(mul(local2WorldTranspose,localCoords));

    Unity采用的压缩方式是DXT5nm。有A和G两个通道。对于法线(x,y,z) A对应x,G对应y。范围依然是[0,1], 依然需要转换至[-1,1]。

  6. 计算光照,并输出:

  

float3 diffuseReflection =  saturate( dot(normalDirection,lightDirection));

return float4(texN.xyz*diffuseReflection,1.0);

源代码:

  1 Shader "JQM/NoamalMap_1"
  2 {
  3     Properties
  4     {
  5         _MainTex ("Texture", 2D) = "white" {}                
  6         _BumpMap ("Normal Texture", 2D) = "bump" {}        
  7         _BumpDepth("_Bump Depth",Range(-2,2.0)) = 1
  8     }
  9 
 10     SubShader
 11     {
 12 
 13         Pass
 14         {
 15             Tags { "LightMode"="ForwardBase" }
 16 
 17             CGPROGRAM
 18             #pragma vertex vert
 19             #pragma fragment frag
 20             //#pragma exclude_renderers flash //给指定平台编译
 21             
 22             #include "UnityCG.cginc"
 23 
 24             //使用自定义变量
 25             sampler2D _MainTex;
 26             float4 _MainTex_ST;
 27             sampler2D _BumpMap;
 28             float4 _BumpMap_ST;
 29             uniform float _BumpDepth;
 30 
 31             //使用Unity定义的变量
 32             uniform float4 _LightColor0;
 33 
 34             //输入结构体
 35             struct vertexInput{
 36                 float4 vertex:POSITION;
 37                 float3 normal:NORMAL;
 38                 float4 texcoord:TEXCOORD0;
 39                 float4 tangent:TANGENT;
 40             };
 41 
 42             //输出结构体
 43             struct vertexOutput{
 44                 float4 pos:SV_POSITION;
 45                 float4 tex:TEXCOORD0;
 46                 float4 posWorld:TEXCOORD1;
 47                 float3 normalWorld:TEXCOORD2;
 48                 float3 tangentWorld:TEXCOORD3;
 49                 float3 binormalWorld:TEXCOORD4;
 50             };
 51 
 52             vertexOutput vert (vertexInput v)
 53             {
 54                 vertexOutput o;
 55 
 56                 o.normalWorld =  normalize( mul(float4(v.normal,0.0),_World2Object).xyz);
 57                 o.tangentWorld =  normalize( mul(_Object2World, v.tangent).xyz);
 58                 o.binormalWorld =  normalize( cross(o.normalWorld,o.tangentWorld)*v.tangent.w);
 59 
 60                 o.posWorld = mul(_Object2World, v.vertex);
 61                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 62                 o.tex = v.texcoord;
 63 
 64                 return o;
 65             }
 66             
 67             fixed4 frag (vertexOutput i) : COLOR
 68             {
 69                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz- i.posWorld.xyz);
 70                 float3 lightDirection; 
 71                 float atten;
 72 
 73                 if(_WorldSpaceLightPos0.w==0.0)//平行光
 74                 {
 75                     atten = 1.0;
 76                     lightDirection = normalize(_WorldSpaceLightPos0.xyz);
 77                 }
 78                 else
 79                 {
 80                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz -i.posWorld.xyz;
 81                     float distance = length(fragmentToLightSource);
 82                     atten  = 1.0/distance;
 83                     lightDirection = normalize(fragmentToLightSource);
 84                 }
 85 
 86                 //Texture Map
 87                 float4 tex  = tex2D(_MainTex,i.tex.xy*_MainTex_ST.xy+_MainTex_ST.zw);
 88                 float4 texN  = tex2D(_BumpMap,i.tex.xy*_BumpMap_ST.xy+_BumpMap_ST.zw);
 89 
 90                 //UnpackNormal [0,1] 转换成[-1,1]
 91                 float3 localCoords = float3(2.0*texN.ag-float2(1.0,1.0),0.0);
 92                 localCoords.z = _BumpDepth;
 93 
 94                 //normal transpose matrix
 95                 float3x3 local2WorldTranspose=float3x3(
 96                     i.tangentWorld,
 97                     i.binormalWorld,
 98                     i.normalWorld
 99                 );
100                  
101                 
102                 ////calculate  normal direction
103                 float3 normalDirection = normalize(mul(local2WorldTranspose,localCoords));                 
104                 ////灯光
105                 float3 diffuseReflection =  saturate( dot(normalDirection,lightDirection));
106 
107                 
108                 return float4(texN.xyz*diffuseReflection,1.0);
109 
110                 
111             }
112             ENDCG
113         }
114     }
115 }

纹理+材质颜色+高光+边缘光+漫反射+环境光+法线贴图:

技术分享

源代码:

  1 Shader "JQM/NoamalMap"
  2 {
  3     Properties
  4     {
  5         _Color("Color", color) = (1.0,1.0,1.0,1.0)
  6         _MainTex ("Texture", 2D) = "white" {}                
  7         _BumpMap ("Normal Texture", 2D) = "bump" {}        
  8         _BumpDepth("_Bump Depth",Range(-2,2.0)) = 1
  9         _SpecColor("Specular Color", color) = (1.0,1.0,1.0,1.0)
 10         _Shininess("Shininess",float) = 10
 11         _RimColor("Rim Coloe Color", color) = (1.0,1.0,1.0,1.0)
 12         _RimPower("Rim Power",Range(0.1,10.0)) = 3.0
 13     }
 14 
 15     SubShader
 16     {
 17 
 18         Pass
 19         {
 20             Tags { "LightMode"="ForwardBase" }
 21 
 22             CGPROGRAM
 23             #pragma vertex vert
 24             #pragma fragment frag
 25             //#pragma exclude_renderers flash //给指定平台编译
 26             
 27             #include "UnityCG.cginc"
 28 
 29             //使用自定义变量
 30             sampler2D _MainTex;
 31             float4 _MainTex_ST;
 32             sampler2D _BumpMap;
 33             float4 _BumpMap_ST;
 34             uniform float4 _Color;
 35             uniform float4 _SpecColor;
 36             uniform float4 _RimColor;
 37             uniform float _Shininess;
 38             uniform float _RimPower;
 39             uniform float _BumpDepth;
 40 
 41             //使用Unity定义的变量
 42             uniform float4 _LightColor0;
 43 
 44             //输入结构体
 45             struct vertexInput{
 46                 float4 vertex:POSITION;
 47                 float3 normal:NORMAL;
 48                 float4 texcoord:TEXCOORD0;
 49                 float4 tangent:TANGENT;
 50             };
 51 
 52             //输出结构体
 53             struct vertexOutput{
 54                 float4 pos:SV_POSITION;
 55                 float4 tex:TEXCOORD0;
 56                 float4 posWorld:TEXCOORD1;
 57                 float3 normalWorld:TEXCOORD2;
 58                 float3 tangentWorld:TEXCOORD3;
 59                 float3 binormalWorld:TEXCOORD4;
 60             };
 61 
 62             vertexOutput vert (vertexInput v)
 63             {
 64                 vertexOutput o;
 65 
 66                 o.normalWorld =  normalize( mul(float4(v.normal,0.0),_World2Object).xyz);
 67                 o.tangentWorld =  normalize( mul(_Object2World, v.tangent).xyz);
 68                 o.binormalWorld =  normalize( cross(o.normalWorld,o.tangentWorld)*v.tangent.w);
 69 
 70                 o.posWorld = mul(_Object2World, v.vertex);
 71                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 72                 o.tex = v.texcoord;
 73 
 74                 return o;
 75             }
 76             
 77             fixed4 frag (vertexOutput i) : COLOR
 78             {
 79                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz- i.posWorld.xyz);
 80                 float3 lightDirection; 
 81                 float atten;
 82 
 83                 if(_WorldSpaceLightPos0.w==0.0)//平行光
 84                 {
 85                     atten = 1.0;
 86                     lightDirection = normalize(_WorldSpaceLightPos0.xyz);
 87                 }
 88                 else
 89                 {
 90                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz -i.posWorld.xyz;
 91                     float distance = length(fragmentToLightSource);
 92                     atten  = 1.0/distance;
 93                     lightDirection = normalize(fragmentToLightSource);
 94                 }
 95 
 96                 //Texture Map
 97                 float4 tex  = tex2D(_MainTex,i.tex.xy*_MainTex_ST.xy+_MainTex_ST.zw);
 98                 float4 texN  = tex2D(_BumpMap,i.tex.xy*_BumpMap_ST.xy+_BumpMap_ST.zw);
 99 
100                 //UnpackNormal [0,1] 转换成[-1,1]
101                 float3 localCoords = float3(2.0*texN.ag-float2(1.0,1.0),0.0);
102                 localCoords.z = _BumpDepth;
103 
104                 //normal transpose matrix
105                 float3x3 local2WorldTranspose=float3x3(
106                     i.tangentWorld,
107                     i.binormalWorld,
108                     i.normalWorld
109                 );
110                  
111                 //calculate  normal direction
112                 float3 normalDirection = normalize(mul(local2WorldTranspose,localCoords));
113                 //float3 normalDirection = normalize(mul(localCoords,local2WorldTranspose));
114 
115                 //灯光
116                 float3 diffuseReflection = atten * _LightColor0.xyz *  saturate( dot(normalDirection,lightDirection));
117                 float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb*saturate( dot(normalDirection,lightDirection))*pow(saturate(dot(reflect(-lightDirection,normalDirection),viewDirection)),_Shininess);
118                 
119                 //Rim Light
120                 float rim= 1-dot(normalize(viewDirection),normalDirection);
121                 float3 rimLighting = atten * _LightColor0.xyz * _RimColor.rgb*saturate(dot(normalDirection,lightDirection))*pow(rim,_RimPower);
122 
123                 float3 lightFinal = rimLighting + diffuseReflection+specularReflection+UNITY_LIGHTMODEL_AMBIENT.xyz;
124 
125                 
126 
127                 return float4(tex*lightFinal*_Color.xyz,1.0);
128                 
129             }
130             ENDCG
131         }
132 
133         Pass
134         {
135             Tags { "LightMode"="ForwardAdd" }
136             Blend One One
137 
138             CGPROGRAM
139             #pragma vertex vert
140             #pragma fragment frag
141             //#pragma exclude_renderers flash //给指定平台编译
142             
143             #include "UnityCG.cginc"
144 
145             //使用自定义变量
146             sampler2D _MainTex;
147             float4 _MainTex_ST;
148             sampler2D _BumpMap;
149             float4 _BumpMap_ST;
150             uniform float4 _Color;
151             uniform float4 _SpecColor;
152             uniform float4 _RimColor;
153             uniform float _Shininess;
154             uniform float _RimPower;
155             uniform float _BumpDepth;
156 
157             //使用Unity定义的变量
158             uniform float4 _LightColor0;
159 
160             //输入结构体
161             struct vertexInput{
162                 float4 vertex:POSITION;
163                 float3 normal:NORMAL;
164                 float4 texcoord:TEXCOORD0;
165                 float4 tangent:TANGENT;
166             };
167 
168             //输出结构体
169             struct vertexOutput{
170                 float4 pos:SV_POSITION;
171                 float4 tex:TEXCOORD0;
172                 float4 posWorld:TEXCOORD1;
173                 float3 normalWorld:TEXCOORD2;
174                 float3 tangentWorld:TEXCOORD3;
175                 float3 binormalWorld:TEXCOORD4;
176             };
177 
178             vertexOutput vert (vertexInput v)
179             {
180                 vertexOutput o;
181 
182                 o.normalWorld =  normalize( mul(float4(v.normal,0.0),_World2Object).xyz);
183                 o.tangentWorld =  normalize( mul(_Object2World, v.tangent).xyz);
184                 o.binormalWorld =  normalize( cross(o.normalWorld,o.tangentWorld)*v.tangent.w);
185 
186                 o.posWorld = mul(_Object2World, v.vertex);
187                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
188                 o.tex = v.texcoord;
189 
190                 return o;
191             }
192             
193             fixed4 frag (vertexOutput i) : COLOR
194             {
195                 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz- i.posWorld.xyz);
196                 float3 lightDirection; 
197                 float atten;
198 
199                 if(_WorldSpaceLightPos0.w==0.0)//平行光
200                 {
201                     atten = 1.0;
202                     lightDirection = normalize(_WorldSpaceLightPos0.xyz);
203                 }
204                 else
205                 {
206                     float3 fragmentToLightSource = _WorldSpaceLightPos0.xyz -i.posWorld.xyz;
207                     float distance = length(fragmentToLightSource);
208                     atten  = 1.0/distance;
209                     lightDirection = normalize(fragmentToLightSource);
210                 }
211 
212                 //Texture Map
213                 float4 texN  = tex2D(_BumpMap, i.tex.xy*_BumpMap_ST.xy+_BumpMap_ST.zw);
214 
215                 //UnpackNormal 
216                 float3 localCoords = float3(2.0*texN.ag-float2(1.0,1.0),0.0);
217                 localCoords.z = _BumpDepth;
218 
219                 //normal transpose matrix
220                 float3x3 local2WorldTranspose=float3x3(
221                     i.tangentWorld,
222                     i.binormalWorld,
223                     i.normalWorld
224                 );
225                  
226                 //calculate  normal direction
227                 float3 normalDirection = normalize(mul(local2WorldTranspose,localCoords));
228                 //float3 normalDirection = normalize(mul(localCoords, local2WorldTranspose));
229 
230                 //灯光
231                 float3 diffuseReflection = atten * _LightColor0.xyz *  saturate( dot(normalDirection,lightDirection));
232                 float3 specularReflection = diffuseReflection * _SpecColor.rgb*saturate( dot(normalDirection,lightDirection))*pow(saturate(dot(reflect(-lightDirection,normalDirection),viewDirection)),_Shininess);
233                 
234                 //Rim Light
235                 float rim= 1-dot(normalize(viewDirection),normalDirection);
236                 float3 rimLighting = _LightColor0.xyz * _RimColor.rgb*saturate(dot(normalDirection,lightDirection))*pow(rim,_RimPower);
237 
238                 float3 lightFinal = rimLighting + diffuseReflection+specularReflection;
239 
240                 return float4(lightFinal*_Color.xyz,1.0);
241             }
242             ENDCG
243         }
244         
245     }
246 }

 

 

    

NormalMap 法线贴图

标签:

原文地址:http://www.cnblogs.com/jqm304775992/p/4898550.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!