在Unity3d 中,右键创建 一个 Shader ,这个Shader 中会默认包含一些代码。这个默认的代码就为我们创建了 基本的漫反射着色器,并且接收一个 纹理。
上一篇中,为了了解 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 后缀。
这正是这一次要学习的,创建自定义的光照模型的时候,光照模型的函数名,函数定义 都是有规定的。
以我要创建的 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
然后完成 光照模型函数。
//不需要视角方向的前向着色 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 光照模型函数中,使用了 max 点积函数:
点积函数 ( dot product function ) 用来比较 两个向量在 空间里的方向。max ( A , B ) 其实就是求 A 向量 和 B 向量 夹角的 Cos 值。这里就是 法线向量 和 灯光方向向量。
Cos 值 :值越大,两个向量 夹角 越小,
Cos 值 = 1的时候,两个向量 平行并垂直指向你。这时光照垂直照射,就像正午的太阳。
Cos值 =-1时,平行并且背离你。 就像太阳正好照着地球的另一边。
Cos 值 = 0时,表示垂直,这下就没有光照了。就像傍晚,然后黑夜。
然后在代码中,将 SurfaceOutput 结构 提供的数据 和 光照数据 相乘 。光照数据来自 Unity ,SurfaceOutput 数据来自我们在编辑器中的设置。
然后再和 上面计算出来的 Cos 值 进行相乘。这样才会随着物体与 光线的角度的差异而表面受光照强度不同。
我发现,这上面的自定义的 漫反射光照模型函数 是和 Lighting.cginc 中的 Lambert 光照模型函数是一样的……
汗。。
不过这一次我就是学习来自定义一个光照模型函数,所以目的达到了哦。后面就能在这一次的基础上修改出自己的光照模型函数了。
例子工程下载:
http://pan.baidu.com/s/1qXtYPre