Unity Shader 入门笔记vol1--第一束光

前面的碎碎念

本人从 2024 年 3 月初识技术美术,然后一边烦恼一边在各大平台乱逛,想要了解这个职位究竟如何。期间也断断续续学了一点点,就这么犹犹豫豫半年过去了,直至前阵子总算清除了所有的迷惘,并且学过了那些基础的光照模型。

本人是按照 AP01 的课程来入门的,目前刚好处于学过光照模型,然后做过第一个 DOTA2 大作业的状态,勉勉强强可以说是入了半个门了。接下来用我的节奏讲讲我的一些理解。

本人在学习技术美术的过程始终贯彻一个原则——“装懂”,听的懂的很好,听不懂的先装作懂了先用着,秉持一个能跑就行,先跟着走,之后再尝试理解。因此直到现在那些 输入结构 、 输出结构 、 像素 Shader 之类的东西我还没弄懂。

首先是渲染流程,我还没弄明白,只是在脑中有一个懵懂的概念,因此先贴上PPT。

image-20241008201244509

第一束光-Lambert

  • 向量 ( Vector ):既有大小 也有方向的量;如:力,速度等。

    理论上不存在没有大小,只有方向的量;但存在大小无现实意义的量,我们多把它归一化处理,在 Shader 中如果出现大于 1 的量会比较危险。

  • 点乘/点积/Dot :两向量间的一种运算方式,结果为一标量,具有良好的几何含义。

    结果的几何意义为:一个向量在另一向量上的投影长度;

结果的图形学表现为:两向量 方向同 结果= 1 (白色); 方向反 结果= 1 (黑色); 垂直 结果= 0 (黑色)

根据向量点乘的图形学含义 我们令:

• 模型表面的垂直方向为向量 nDir 即:法线方向( NormalDirection );
• 令光照方向的反方向为向量 lDir 即: LightDir ,光方向(由物体表面指向光源);
• 令 nDir · lDir (两者点乘) 结果为像素输出;

则有下图的光照表现

image-20241008173452496

其中:

  • 最亮处:值为1,纯白;

  • 明暗交界处:值为0,纯黑;

  • 暗部:值为负数,亦为黑;

image-20241008173636516

负数是个无意义的亮度,所以我们通常把结果为负数的值截断,都改为 0 :

Max(0 , nDir · IDir);

即为 兰伯特光照模型 ( Lambert )

image-20241008173818184

截断负值的做法还可以用 Clamp 0-1 。

Shader Forge 实现

我们在 Shader Forge 中新建一个 Unlit 模型作为基础,我们所有的效果都靠自己写,不涉及 Unity 的黑盒的东西。

此处观察 Shader Forge 中的 Light Dir. 的图片就可以理解光方向其实是 “光方向的反方向”

image-20241008174142424

我们先给场景内添加个球,然后对这个 Shader 右键 >> Create >> Material ,用它创建一个材质。然后拖动这个材质到球上,就把这个材质附给这只球了。

image-20241008174309616

HalfLambert

我们现在有了 兰伯特光照模型,感觉这个 兰伯特 的暗部全是一片死黑。那么有一种改进方法。

如下图,对兰伯特的结果 [-1,1] * 0.5 + 0.5 ,得到一个 [0,1] 的结果,这就是半兰伯特( HalfLambert )。它的优缺点如图所示,虽然比 Lambert 更透气,但是显然它不符合我们常见的光照情况,因为半兰伯特是一个经验模型,他并不是由物理公式推理而来的。实际上之前版本的 cs 就使用了半兰伯特模型。

image-20241008175019657

Shader Forge 实现

image-20241008202154128

image-20241008175532969

这里的 Clamp 0-1 等效于之前所做的 Max0

半兰伯特 放到这个球上还是挺漂亮的。

HalfLambert 调子映射

image-20241008175725954

考虑对半兰伯特做映射。上面讲点积时提到,点积的结果是一维的,但是要对一张贴图(RampTex)采样需要一套 UV (2维),就是说必须要有2个值才能去采样一张贴图。想像那些模型展 UV 时,把模型拆开然后摊大饼,在U坐标V坐标摊开,然后去做贴图之类的东西。这不可能只摊成一条线,那样采样贴图是不可能的。

我们现在有了 HalfLambert 这个一维的常量,那么如何得到一个二维向量呢?

这里就要用到 Append 节点,我们把 2 个 标量/一维向量 Append ,就变成了一个 二维向量(即有2个分量的向量) ,一个 二维向量 和一个 标量/一维向量 Append 就变成了三维向量,最多到四维,理解为 RGBA 4个通道。(另外 Component Mask 节点是拆分量的)

那么我们可以把 HalfLambert 和一个常量 Append 成一个二维向量,把它作为 UV 去采样一张贴图(RampTex),采样的结果连接到 Shader Forge 里的 Emission 就完成了。

这里一般来说贴图的渐变是横坐标变换,所以把半兰伯特作为横坐标,另外给的常量作为纵坐标。

然后我们可以用 HalfLambert 做一个简单的卡通渲染(简称”卡渲“)。

贴图的特点

3 阶明度,过渡卡硬。

暗部做色相变化,少明度变化。

明暗交界线附近由于有偏红的 SSS 效果,光能守恒的原因可能在明暗交界线附近的亮部,会些许泛蓝。

这张贴图尺寸不用很大,采样贴图是一个比较费的操作,一般128*128即可。

image-20241008200032605

image-20241008195655554

image-20241008195728422

可能遇到的问题

  • 最亮处有暗点:把渐变纹理的 Wrap Mode 从Repeat 改为 Clamp 模式。

需要注意的是,我们需要把渐变纹理的 Wrap Mode 设为 Clamp 模式,以防止对纹理进行采样时由于浮点数精度而造成的问题。图 7.19给出了 Wrap Mode分别为 Repeat和 Clamp模式的效果对比。 可以看出,左图(使用 Repeat 模式)中在高光区域有一些黑点。这是由浮点精度造成的,当我们使用 fixed2(halfLamberthalfLambert)对渐变纹理进行采样时,虽然理论上 halfLambert 的值在【0,1】之间,但可能会有 1.000 01 这样的值出现。如果我们使用的是 Repeat 模式,此时就会舍弃整数部分,只保留小数部,得到的值就是 0.000 01,对应了渐变图中最左边的值,即黑色。因此,就会出现图中这样在高光区域反而有黑点的情况。我们只需要把渐变纹理的 Wrap Mode 设为 Clamp 模式就可以解决这种问题。

——《Unity Shader 入门精要》

  • 描边有锯齿:卡渲一般标配抗锯齿后处理,暂时不用考虑。

附带一些卡渲的不同风格

image-20241008200709106

image-20241008200718689

image-20241008200722701

image-20241008200740445

image-20241008200743790

image-20241008200821427

image-20241008200834362

image-20241008200843577

image-20241008200852196

归档 友链
arrow_up
theme