Unity3D ShaderLab 静态贴图光照模型

 Unity3D ShaderLab 静态贴图光照模型

其实在unity的光照模型中,我们可以把光照讯息烘培进入一个2D贴图,来实现着色器的光照效果。

下面是在unity中关闭灯光和打开灯光的对比效果。所以这类着色器的缺点就是不会随着光源变化效果。

 

 

 

接下来,我们开始创建,首先通过软件MaCrea来制作我们的2D光照贴图,MaCrea软件

 

通过该软件可以快速制作一个完整的发光球体平面图。

软件地址:http://pan.baidu.com/s/1bnD7wkv

软件视频教学地址:http://pan.baidu.com/s/1c0rQDva

完成静态光照贴图的制作后。在unity中创建ShaderMaterial

直接打开Shader脚本编辑:

1>Properties: 

1 Properties {
2 
3 _MainTint("Diffuse Color",Color) = (1,1,1,1)
4 
5 _MainTex ("Base (RGB)", 2D) = "white" {}
6 
7 _NormalMap("Normal Map",2D) = ""{}
8 
9 }

2>SubShader:

 1 CGPROGRAM
 2 
 3 #pragma surface surf Unlit vertex:vert
 4 
 5  
 6 
 7 float4 _MainTint;
 8 
 9 sampler2D _MainTex;
10 
11 sampler2D _NormalMap;
12 
13 struct Input {
14 
15 float2 uv_MainTex;
16 
17 float2 uv_NormalMap;
18 
19 float3 tan1;
20 
21 float3 tan2;
22 
23 };

//因为我们要使用单独的球体贴图来实现光照,所以我们无需使用Lambert光照函数,只需要申明自定义无光亮的光照函数;

3>光照函数

 1 inline fixed4 LightingUnlit(SurfaceOutput s, fixed3 lightDir, fixed3 atten){
 2 
 3 fixed4 c= fixed4(1,1,1,1);
 4 
 5 c.rgb = c*s.Albedo;
 6 
 7 c.a = s.Alpha;
 8 
 9 return c;
10 
11 }

//我们只希望通过外部物体来产生阴影,因为该着色器不受光源的;

4>计算球面贴图

 1 void vert(inout appdata_full v, out Input o){
 2 
 3 UNITY_INITIALIZE_OUTPUT(Input, o);
 4 
 5  
 6 
 7 TANGENT_SPACE_ROTATION ;
 8 
 9 o.tan1 = mul(rotation,UNITY_MATRIX_IT_MV[0].xyz);
10 
11 o.tan2 = mul(rotation,UNITY_MATRIX_IT_MV[1].xyz);
12 
13 }

//为了正确的检索到球面贴图,我们需要把正切旋转矩阵乘以当前模型的逆转模型视图;

5>完善surf

 1 void surf (Input IN, inout SurfaceOutput o) {
 2 
 3 float3 normals = UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
 4 
 5 o.Normal = normals;
 6 
 7  
 8 
 9 float2 litSphereUV;
10 
11 litSphereUV.x = dot(IN.tan1,o.Normal);
12 
13 litSphereUV.y = dot(IN.tan2,o.Normal);
14 
15  
16 
17 half4 c = tex2D (_MainTex, litSphereUV*0.5+0.5);
18 
19 o.Albedo = c.rgb*_MainTint;
20 
21 o.Alpha = c.a;
22 
23 }

 

通过以上的步骤,我们完成这个静态的光照模型。返回unity中简单设置后,就可以看出效果了。

 

在上面的过程中,最主要的是vert函数,因为在这个函数里,我们把旋转切向量和逆转模型视图矩阵相乘,在赋值给o.tan1o.tan2

这个计算就是把向量弯曲到何时的位置来检索球面的贴图。而逆转模型视图则是我们利用unity内置的值。

通过上面的检索传递后,我们简单的将IN.tan1IN.tan2的值作为球面贴图纹理检索的uv值,

我们可以直接使用input结构体中的值,因为我们也在vert函数中将这些值传递进去了。

 

 1 Shader "91YGame/LightStatic" {
 2     Properties {
 3         _MainTint("Diffuse Color",Color) = (1,1,1,1)
 4         _MainTex ("Base (RGB)", 2D) = "white" {}
 5         _NormalMap("Normal Map",2D) = ""{}
 6     }
 7     SubShader {
 8         Tags { "RenderType"="Opaque" }
 9         LOD 200
10         
11         CGPROGRAM
12         #pragma surface surf Unlit vertex:vert
13 
14         float4 _MainTint;
15         sampler2D _MainTex;
16         sampler2D _NormalMap;
17 
18         struct Input {
19             float2 uv_MainTex;
20             float2 uv_NormalMap;
21             float3 tan1;
22             float3 tan2;
23         };
24 
25 
26 
27         inline fixed4 LightingUnlit(SurfaceOutput s, fixed3 lightDir, fixed3 atten){
28             fixed4 c= fixed4(1,1,1,1);
29             c.rgb = c*s.Albedo;
30             c.a = s.Alpha;
31             return c;
32         }
33 
34         void vert(inout appdata_full v, out Input o){
35             UNITY_INITIALIZE_OUTPUT(Input, o);
36 
37             TANGENT_SPACE_ROTATION;
38             o.tan1 = mul(rotation,UNITY_MATRIX_IT_MV[0].xyz);
39             o.tan2 = mul(rotation,UNITY_MATRIX_IT_MV[1].xyz);
40         }
41 
42         void surf (Input IN, inout SurfaceOutput o) {
43             float3 normals = UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
44             o.Normal = normals;
45 
46             float2 litSphereUV;
47             litSphereUV.x = dot(IN.tan1,o.Normal);
48             litSphereUV.y = dot(IN.tan2,o.Normal);
49 
50             half4 c = tex2D (_MainTex, litSphereUV*0.5+0.5);
51             o.Albedo = c.rgb*_MainTint;
52             o.Alpha = c.a;
53         }
54         ENDCG
55     } 
56     FallBack "Diffuse"
57 }

 

 

 

原文地址:https://www.cnblogs.com/2Yous/p/4246208.html