Unity Shaders and Effects Cookbook (1-2)创建自定义漫反射光照模型
在Unity3D中,通过右键操作可以创建一个Shader,该Shader默认包含一些代码。这些默认代码为我们创建了基本的漫反射着色器,并且可以接收一个纹理。
在上一篇文章中,为了了解Shader最基本的结构,我们删掉了其中的一些代码。本次我们将学习如何创建自定义的漫反射光照模型。
1. 默认Shader内容分析
首先,让我们来看一下默认的Shader内容(即基本的漫反射着色器Lambert光照模型):
Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert // 告诉着色器使用哪个光照模型来计算,这里默认使用了Lighting.cginc中的Lambert光照模型
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
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后缀。
这其实引出了我们本次要学习的重点:在创建自定义的光照模型时,光照模型的函数名和函数定义是有规定的。
2. 自定义光照模型函数的规定
以我们要创建的BasicDiffuse漫反射光照模型为例,在Unity Shader中,光照模型函数名的格式规定如下:
// 不需要视角方向的前向着色
inline half4 LightingBasicDiffuse(SurfaceOutput so, half3 lightDir, half atten)
{
half4 color = (0,0,0,0);
return color;
}
// 需要视角方向的前向着色
inline half4 LightingBasicDiffuseWithViewDir(SurfaceOutput so, half3 lightDir, half3 viewDir, half atten)
{
half4 color = (0,0,0,0);
return color;
}
// 需要使用延迟着色
inline half4 LightingBasicDiffuse_PrePass(SurfaceOutput so, half4 light)
{
half4 color = (0,0,0,0);
return color;
}
编写好对应的光照模型函数之后,我们需要在Shader中指定它为当前使用的光照模型。具体做法是将:
#pragma surface surf Lambert
修改为:
#pragma surface surf BasicDiffuse
这样就使用了不需要视角方向的前向着色器。
3. 完成光照模型函数
接下来,我们完成BasicDiffuse光照模型函数:
// 不需要视角方向的前向着色
inline half4 LightingBasicDiffuse(SurfaceOutput s, half3 lightDir, half atten)
{
float difLight = max(0, dot(s.Normal, lightDir));
half4 color = (0,0,0,0);
color.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
color.a = s.Alpha;
return color;
}
从这个BasicDiffuse光照模型函数中可以看出,光照模型函数是在Surf函数之后执行的。
在BasicDiffuse光照模型函数中,使用了max点积函数。点积函数(dot product function)用于比较两个向量在空间里的方向。max(A, B)实际上是求A向量和B向量夹角的Cos值,这里的两个向量分别是法线向量和灯光方向向量。
Cos值的含义
- 当Cos值越大时,两个向量的夹角越小。
- 当Cos值等于1时,两个向量平行并垂直指向你,此时光照垂直照射,就像正午的太阳。
- 当Cos值等于 -1时,两个向量平行并且背离你,就像太阳正好照着地球的另一边。
- 当Cos值等于0时,表示两个向量垂直,此时没有光照,就像傍晚到黑夜的状态。
在代码中,我们将SurfaceOutput结构提供的数据和光照数据相乘,光照数据来自Unity,SurfaceOutput数据来自我们在编辑器中的设置。然后再和上面计算出来的Cos值进行相乘,这样物体表面的受光照强度就会随着物体与光线角度的差异而不同。
4. 总结
经过分析,我们发现上面自定义的漫反射光照模型函数和Lighting.cginc中的Lambert光照模型函数是一样的。不过,本次学习的目的是掌握自定义光照模型函数的创建方法,我们已经达到了这个目的。后续我们可以在此基础上修改出自己独特的光照模型函数。
5. 例子工程下载
你可以通过以下链接下载例子工程: https://pan.baidu.com/s/1boEvkFd ,密码: 9hm6