其实在unity的光照模型中,我们可以把光照讯息烘培进入一个2D贴图,来实现着色器的光照效果。
下面是在unity中关闭灯光和打开灯光的对比效果。所以这类着色器的缺点就是不会随着光源变化效果。
接下来,我们开始创建,首先通过软件MaCrea来制作我们的2D光照贴图,MaCrea软件
通过该软件可以快速制作一个完整的发光球体平面图。
完成静态光照贴图的制作后。在unity中创建Shader,Material。
直接打开Shader脚本编辑:
1>roperties:
- <font face="新宋体" size="2">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 }</font>
复制代码
2>SubShader:
- <font face="新宋体" size="2"> 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 };</font>
复制代码
//因为我们要使用单独的球体贴图来实现光照,所以我们无需使用Lambert光照函数,只需要申明自定义无光亮的光照函数;
3>光照函数
- <font face="新宋体" size="2"> 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 }</font>
复制代码
//我们只希望通过外部物体来产生阴影,因为该着色器不受光源的;
4>计算球面贴图
- <font face="新宋体" size="2"> 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 }</font>
复制代码
//为了正确的检索到球面贴图,我们需要把正切旋转矩阵乘以当前模型的逆转模型视图;
5>完善surf
- <font face="新宋体" size="2">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 }</font>
复制代码
通过以上的步骤,我们完成这个静态的光照模型。返回unity中简单设置后,就可以看出效果了。
在上面的过程中,最主要的是vert函数,因为在这个函数里,我们把旋转切向量和逆转模型视图矩阵相乘,在赋值给o.tan1和o.tan2。
这个计算就是把向量弯曲到何时的位置来检索球面的贴图。而逆转模型视图则是我们利用unity内置的值。
通过上面的检索传递后,我们简单的将IN.tan1和IN.tan2的值作为球面贴图纹理检索的uv值,
我们可以直接使用input结构体中的值,因为我们也在vert函数中将这些值传递进去了。
- <font face="新宋体" size="2">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 }</font>