Summary
表面着色器真的非常方便,特别是在处理光照时,表面着色器可以使用PBR模型快速实现物理光照效果。但是有时候我们可能想实现其他一些光照效果,例如卡通风格的。这时候我们可以使用自定义光照函数来满足我们的需求。
本篇主要介绍表面着色器特有的一些功能。但是光照处理的基本原理可以应用到其他着色器中。只不过Unity会为表面着色器生成一个基本的可复用的光照框架,如果我们使用其他着色器,那么必须手动补全这部分代码,但是这些并不是本文的重点,所以不做赘述。
如果你是一个初学者,建议你从第一章开始看。
Use Custom Lighting Function
首先我们需要将光照模型设置为我们自定义的光照函数。
1 | //表面着色器 |
然后我们添加我们的自定义光照函数。光照函数的名字结构是LightingX
,其中X
是上面定义的光照函数,这里是Custom
。在下面的自定义光照函数中使用的SurfaceOutput
结构体,实际上是由surf
表面着色器函数返回的数据,两者最终的数据结构必须一致。另外还有光照方向、以及光照衰减度,衰减度在后面会介绍。
1 | //自定义光照函数,针对每个光源都会处理一遍 |
SurfaceOutput
和SurfaceOutputSstandard
都是Unity预定义的数据结构,前者是针对非物理渲染的,后者是提供了物理渲染的基本参数。当然你也可以把他们当做是一个参考模板,然后实现自己的数据结构。使用的方法是,先在表面着色器函数中对该结构赋值,然后在自定义光照函数中使用。因为SurfaceOutput
不包含光滑度、以及金属度的属性,所以在表面着色器删除对这两者的赋值。
//表面着色器
void surf (Input i, inout SurfaceOutput o) {
//纹理采样
fixed4 col = tex2D(_MainTex, i.uv_MainTex);
col *= _Color;
o.Albedo = col.rgb;
//o.Emission = _Emission;
}
现在我们有了自己的光照函数,但是该函数目前返回的是0,所以模型渲染后看不到光照效果。
按理说光照为零的话,整个模型应该是纯黑色,但是我们现在却能看清模型的基本轮廓。这是因为,光照函数处理的是直接光源,但是在模型渲染的时候除了直接光源,还有间接光源作用。其中环境光就是一种间接光源,Unity会自动将天空盒的颜色来当成环境光的一部分,所以我们在环境光的作用下还能看清物体。如果你在Unity编辑器的场景窗口上方选择关闭环境光的按钮,那么整个模型最终就会变成纯黑色,并且其最终显示都完全受我们的自定义光照函数控制。当然这里我保留Unity编辑器的默认设置。
Implement Lighting Ramp
下面我们来实现简单的自定义光照函数。第一步我们先求解表面法向和入射光线方向向量的点乘,这两个参数正好在自定义光照函数的参数列表中。
1 | //自定义光照函数 |
下面我们实现的光照函数非常简单,涵盖了一般通用结构。我们使用光线入射向量来最为纹理纹理采样的参数,并将采样结果当成光源在该点的亮度。
因此我们必须将点乘结果的取值范围从[-1, 1]
映射为[0, 1]
,因为后者是UV的取值范围。
然后我们创建一个叫ramp
的纹理变量。按照前面说的采样方法进行采样。然后在材质面板上设置纹理为半黑半白的图片。
1 | //材质面板 |
下面是我们所用的ramp
纹理。
1 | //自定义光照函数 |
在上图中,模型背光面也能看清模型表面纹理。这还是因为环境光的影响。
为了让效果看起来更好,我们将模型颜色和光照密度相乘、同时应用衰减因子,最终的到一个具有颜色、且强度随距离变化的光源。模型最终的表现也和光源的颜色、和距离相关。
1 | //自定义光照 |
上面已经介绍完了一个完整的自定义光照着色器的实现。我们可以使用不同的ramp
纹理来得到完全不同的渲染风格。比如下面,我们采样冷暖色条纹,实现的卡通效果。图片源于这里
在着色器我们还有一个emission
没有用到,但是模型最终的显示中却受自发光这个变量的影响。
上面这种卡通风格的着色器非常有用,在很多地方可以灵活运用。
自定义光照函数非常强大,但是只能用在前向渲染中。即便是你把渲染路径改为延迟渲染,最终渲染管线依然会把这部分的渲染转移到前向渲染路径中。
1 | Shader "Tutorial/013_CustomSurfaceLighting" { |
希望本篇能帮助你理解表面着色器和自定义光照。
你可以在以下链接找到源码:
https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/013_CustomSurfaceLighting/CustomLighting.shader
希望你能喜欢这个教程哦!如果你想支持我,可以关注我的推特,或者通过ko-fi、或patreon给两小钱。总之,各位大爷,走过路过不要错过,有钱的捧个钱场,没钱的捧个人场:-)!!!