咨询电话:400-810-1418服务与监督电话:400-006-6572

Unity中Diffuse Light漫反射光照diffuse效果教程

发布时间:2019-11-29 09:52:17

Hello all,今天跟大家唠一下unity shader中的diffuse,我们在游戏开发的过程中光照是必不可少的,而为了使游戏更加真实,获得更好的体验,也会模拟因光照产生的各种镜面反射(sprcular),漫反射(diffuse),所以这里我们先讨论一下漫反射(diffuse)。

1、漫反射原理

如果我们的物体表面凹凸不平,其表面上每个点的法线方向就不一致。当一束外来光照射到这个物体表面的时候,入射光线都是平行的,但是每个点由于法线方向不一致而产生不同的反射光线,如图;

1-1.webp.jpg

如果照在物体上的入射角为0的时候,说明光线垂直于物体表面,看到的表面就会越亮,即漫反射光强也是最大的;当入射角为九十度时,即光线与物体表面平行,物体接收不到任何光线,就会产生暗部。

而漫反射光的强度到底是怎么样子计算的呢?

漫反射光的强度可以用lambert(可参考维基百科)定律进行计算,即漫反射的光强仅与入射光的方向和反射点处表面法线夹角的余弦成正比,即;

Idiffuse=Id*Kd*cosθ

Idiffuse就是表面点的漫反射光强,Id是点光源强度,Kd(0<Kd<1)表示物体表面该点对漫反射光的反射属性,θ是入射光线的方向与物体表面该点处法线N的夹角,或称为入射角(0≤θ≤90°),而根据向量点乘N*L=|N|*|L|cosΘ (N是法线,L是太阳光的反方向)。如果对N向量和L向量进行归一化处理的话,即让N*L这个向量的模等于1,就会得到N*L= cosθ;而对于上面公式中,Id和Kd对同一物体在同一个光照下参数值都是一样的,所以影响一个物体不同点的漫反射强度的就只有N*L了。

下图就是最简单的diffuse效果,一束光打在小球上因为表面法线不一样而呈现不同的明暗效果。

1-2.webp.jpg

所以接下来我们就在引擎中亲手实现上面这种diffuse效果

2、场景设置

新开一个unity场景,拉一个小球在中间,修改场景light设置,去掉Sky Material,Environment Lighting设置为color(避免小球受环境光的影响),并将color改完全黑,然后Environment Reflection也设置为Custom。

2-1.webp.jpg

此时场景中的效果应该如图,

2-2.webp.jpg

此时小球的并不只受漫反射光,根据亮部可以看到还有镜面反射效果。

现在我们就开始用可视化shader编程为其添加一个shader,让他只有一个diffuse的效果。由于只是一个简单的材质,所以官方的shader graph和野生的shader forge都可以使用。这里的举例使用shader graph,毕竟亲生的以后更新比较方便。

创建一个新的shader graph并双击打开

2-3.webp.jpg

打开进去里面是一个默认的shader预设值PBR Master,对于今天所以呈现的diffuse效果来说,这个预设太过于复杂,加了很多其他的效果,specular等,所以我们要将其删掉,然后创建一个新的node叫做Unlit。

2-4.webp.jpg

然后我们就得到了只有color和alpha的一个Unlit Master(无光的shader)

2-5.webp.jpg

如果更改其color的值,整个shader都会变成这个纯色,而没有阴影高光等

2-6.webp.jpg

所以接下来我们就按照上面说的公式N*L(为简化省略掉了其他点光源强度等数值)来实现diffuse效果。

场景中新建一个材质球material,然后把材质球的shader选成上面我们新建的那个shader名字,然后将其赋给场景中的小球。

2-7.webp.jpg

现在我们就可以在场景中直接看到我的修改shader以后的效果。

先将里面的color值暴露出去,shader中新建Property,并命名为DiffuseColor,然后直接将DiffuseColor拖到编辑器中,就可以看到加载了DiffuseColor的一个Property节点,将节点直接连接到Color中保存这个shader graph,在外部小球material就可以看到我们暴露出去的Diffuse Color。

2-8.webp.jpg

3、添加法向量N

Shader graph中自带有获取物体法向量的节点,Normal Vector,将Normal Vector直接连接到Color中保存以后,场景中的小球颜色就会直接呈现法线的颜色。

3-1.webp.jpg

3-2.webp.jpg

将我们的法线小球的颜色和unity坐标轴对比可以发现,x轴正方向上的小球会更偏红,y轴正方向的会更绿,而z轴的会更蓝,这个因为在轴上的坐标值分别是(1,0,0),(0,1,0)(0,0,1),而这些坐标值所对应的颜色值就是红绿蓝,所以我们的坐标值和法线颜色值是对应的,我们就可以通过颜色值来求得法线值。

3-3.webp.jpg

4、获取L值

法线向量和光源方向的运算是点乘,graph里面对应的节点是dot,所以我们搜索添加dot节点,然后将其中N输入进去

4-1.webp.jpg

输入N以后我们剩下就要给L值,但是怎么获取场景中点光源的L值呢?

在当前shader graph的节点中没有获取光线方向的节点,但是我们可以自己为其输入L参数。新建一个三维property命名为L,然后拉到graph中与N点乘。现在默认L还没有任何取值,即没有光线进入,我们将x的值给个1,说明x轴方向有一束光打过来,就可以在预览里面看到小球产生了明暗变化。

4-2.webp.jpg

当前的效果只是一个明暗变化的效果,如果我们要将diffusecolor加进来与其混合的话,就需要用Multiply将两个值进行相乘然后输入到unlit的color中然后保存。

4-3.webp.jpg

回到场景中在material属性栏可修改color和光源方向的值,我们将光源方向调到(1,1,1),然后就得到了我们经典的lambert光!

4-4.webp.jpg

5、获取L值

我们调节场景中的光方向到(1,0,0),然后观察到其实光的来源方向不是x轴的正方向而是负方向。

5-1.webp.jpg

所以实际上L的值应该取一个负号,因为计算的时候我们不能直接取入射光的方向,如果取得是入射光方向,和法线向量之间的夹角就会是一个大于九十度的钝角,而我们算的入射角一般都是锐角,所以我们要取的是入射光方向的反方向与法线向量的点乘来得到cosθ。

所以我们在节点中将L的值或者点乘以后的值乘以-1即可取得反方向。

5-2.webp.jpg

保存以后就可以在外部material属性中自由调节光源方向啦

以上就实现了我们在开篇所讲的diffuse效果啦。

感恩围观

来源:公众号Thepoly