Unity3D 中,右键创建 一个 Shader ,这个Shader 中会默认包含一些代码。这个默认的代码就为我们创建了 基本的漫反射着色器,并且接收一个 纹理。

 

上一篇中,为了了解 Shader 最基本的结构,我删掉了 里面的一些代码。

这一次来学习创建自定义的漫反射光照模型

 

首先来看下默认的 Shader 内容( 即 基本的漫反射着色器 Lambert 光照模型 )

 

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. Shader "Custom/NewShader" {  
  2.     Properties {  
  3.         _MainTex ("Base (RGB)", 2D) = "white" {}  
  4.     }  
  5.     SubShader {  
  6.         Tags { "RenderType"="Opaque" }  
  7.         LOD 200  
  8.           
  9.         CGPROGRAM  
  10.         #pragma surface surf Lambert // 告诉着色器使用哪个 光照模型来计算,这里默认使用了 Lighting.cginc 中的 Lambert 光照模型  
  11.   
  12.         sampler2D _MainTex;  
  13.   
  14.         struct Input {  
  15.             float2 uv_MainTex;  
  16.         };  
  17.   
  18.         void surf (Input IN, inout SurfaceOutput o) {  
  19.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  20.             o.Albedo = c.rgb;  
  21.             o.Alpha = c.a;  
  22.         }  
  23.         ENDCG  
  24.     }   
  25.     FallBack "Diffuse"  
  26. }  

Shader 结构解析:

#pragma surface surf Lambert :  告诉着色器使用哪个 光照模型来计算,这里默认使用了 Lighting.cginc 中的 Lambert 光照模型

 

上一篇中提到,我们的Shader 引用了 \Editor\Data\CGIncludes 目录下面的 Lighting.cginc ,就像在 C 语言中,调用了其它 文件 中的函数。 

Lambert 这个光照模型 就位于 Lighting.cginc 文件中。

泰课在线

 

在 Lighting.cginc中找到了 Lambert 光照模型相关的函数,但是发现一个问题:

函数名并不只是 Lambert,而是由  Lighting 开头,加上 Lambert ,再加上 _PrePass 或 _DirLightmap 后缀。 

 

这正是这一次要学习的,创建自定义的光照模型的时候,光照模型的函数名,函数定义 都是有规定的。

以我要创建的 BasicDiffuse 漫反射光照模型来讲, Unity Shader 中规定,光照模型函数名的格式是:

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //不需要视角方向的前向着色  
  2. inline half4 LightingBasicDiffuse(SurfaceOutput so,half3 lightDir,half atten)  
  3. {  
  4.     half4 color=(0,0,0,0);  
  5.   
  6.     return color;  
  7. }  
  8.   
  9. //需要视角方向的前向着色  
  10. inline half4 LightingBasicDiffuseWithViewDir(SurfaceOutput so,half3 lightDir,half3 viewDir,half atten)  
  11. {  
  12.     half4 color=(0,0,0,0);  
  13.   
  14.     return color;  
  15. }  
  16.   
  17. //需要使用延迟着色  
  18. inline half4 LightingBasicDiffuse_PrePass(SurfaceOutput so,half4 light)  
  19. {  
  20.     half4 color=(0,0,0,0);  
  21.   
  22.     return color;  
  23. }  

编写好对应的光照模型函数之后,需要在 Shader 中指定 它 为当前使用的光照模型

修改 

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #pragma surface surf Lambert  

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #pragma surface surf BasicDiffuse  

这样就使用了 不需要视角方向 的 前向着色器

然后完成 光照模型函数。

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //不需要视角方向的前向着色  
  2. inline half4 LightingBasicDiffuse(SurfaceOutput s,half3 lightDir,half atten)  
  3. {  
  4.     float difLight = max(0,dot(s.Normal,lightDir) );  
  5.   
  6.     half4 color=(0,0,0,0);  
  7.     color.rgb=s.Albedo * _LightColor0.rgb * ( difLight * atten * 2 );  
  8.     color.a=s.Alpha;  
  9.     return color;  
  10. }  

从这个 BasicDiffuse 光照模型函数中可以看出,光照模型函数是在 Surf 函数之后执行的。

在 BasicDiffuse 光照模型函数中,使用了 max 点积函数:

点积函数 ( dot product function ) 用来比较 两个向量在 空间里的方向。max ( A , B ) 其实就是求 A 向量 和 B 向量 夹角的 Cos 值。这里就是 法线向量 和 灯光方向向量。

Cos 值 :值越大,两个向量 夹角 越小,

Cos 值 = 1的时候,两个向量 平行并垂直指向你。这时光照垂直照射,就像正午的太阳。

Cos值 =-1时,平行并且背离你。 就像太阳正好照着地球的另一边。

Cos 值 = 0时,表示垂直,这下就没有光照了。就像傍晚,然后黑夜。

 

泰课在线

然后在代码中,将 SurfaceOutput 结构 提供的数据 和 光照数据 相乘 。光照数据来自 Unity ,SurfaceOutput 数据来自我们在编辑器中的设置。

然后再和 上面计算出来的 Cos 值 进行相乘。这样才会随着物体与 光线的角度的差异而表面受光照强度不同。

 

我发现,这上面的自定义的 漫反射光照模型函数 是和 Lighting.cginc 中的 Lambert 光照模型函数是一样的……

汗。。

不过这一次我就是学习来自定义一个光照模型函数,所以目的达到了哦。后面就能在这一次的基础上修改出自己的光照模型函数了。

 

例子工程下载:

[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. https://pan.baidu.com/s/1boEvkFd 密码: 9hm6 
  2.