unity-shader-NPR卡通渲染

NPR : Non Photorealistic Rendering, 非真实的渲染, 卡通渲染 是里面的一个范畴


前篇

名词解释

  • Cel Shading - 卡通渲染

卡通渲染的特点通常有三个:一般物体轮廓处有黑色描边;漫反射呈现明显的色块,而不是渐变;高光区域通常是一块突变的白色亮块。

npr代表作品

  • 美术风格 : 军团要塞2,

    • 美式卡通色彩比较丰富,光影表现更真实自然, 明暗交界处过渡. 色彩上比较连续,有渐变色,着色风格很大程度上依赖于艺术家定义的色调(tone)

  • 日式风格 : 崩坏3,

    • 日式卡通风格凸出大范围的纯色色块,光影边界明显,“非真实感” 明显. 往往角色造型更写实,但在着色方面,则趋向于大片大片纯色色块,并有的明暗交界


卡通插件


卡通着色

目前我们实现的卡通人物效果主要由以下几种不同类型的 “子效果” 组成

  • 勾边
  • 梯度漫反射(Ramped Diffuse)
  • 头发高光
  • 边缘光
  • 阴影和面部补光

卡通风格一般可以大致分为日式和美式的 [2], 日式卡通风格凸出大范围的纯色色块,光影边界明显,“非真实感”明显;而美式卡通色彩比较丰富,光影表现更真实自然。下文将探讨实现这两种风格的着色技术。

Cel Shading和Tone Based Shading
先来描述两种经典的NPR着色方法,分别是Cel Shading和Tone Based Shading5

Cel-Shading

Cel Shading的基本思想是把色彩从多色阶降到低色阶,减少色阶的丰富程度,从而实现类似手工着色的效果,具体来说,可以用如下计算方法:

其中,Kd表示模型自身的贴图颜色,celCoord表示法线和光照方向的点积,然后将其点积值 [−1,1][−1,1] 映射至 [0,1][0,1],用作一维色彩表的查找坐标,而paletteTex则是由美术绘制的一维色阶表,一般来说是由几个纯色色块组成的,如下图:

上述做法可以用于模拟卡通渲染的漫反射分量,却并没有考虑到视角相关的光照分量的模拟,因此很难实现类似菲涅尔效果的卡通渲染。实际上,也可以用类似的查找表的思路来视角相关光照分量的色阶离散化6,只需要将一维查找表扩展到二维即可:

相应地,查找坐标也扩展到了二维。

Tone Based Shading

不同于Cel Shading,Tone Based Shading的风格化是基于美术指定的色调插值,并且插值得到的色阶是连续的。首先需要由美术指定冷色调和暖色调,而最终模型的着色将根据法线和光照方向的夹角,在这两个色调的基础上进行插值,具体算法如下:

其中,Kd仍是模型自身色彩贴图,Kblue,Kyellow和alpha,beta则均是自定义的参数。

基于tone based shading绘制的球体

shader
1
2
3
4
5
6
7
8
9
10
11
fixed diff =  dot (worldNormal, worldLightDir);
diff = (diff * 0.5 + 0.5) * atten;

fixed3 k_d = c.rgb * _Color.rgb;

fixed3 k_blue = fixed3(0, 0, _Blue);
fixed3 k_yellow = fixed3(_Yellow, _Yellow, 0);
fixed3 k_cool = k_blue + _Alpha * k_d;
fixed3 k_warm = k_yellow + _Beta * k_d;

fixed3 diffuse = _LightColor0.rgb * (diff * k_warm + (1 - diff) * k_cool);
  • 因为光照方向的原因, 把 冷暖色对调了一下
日式卡通中的着色

引文 [1] 中介绍了游戏《罪恶装备》使用的卡通着色算法(西川善司的两篇文章详述了《罪恶装备》制作流程),表示如下:


描边的几种方法

  1. 基于视点方向的描边

    NdotV, 点乘结果接近于零,那么可以断定这个表面极大概率是侧向( Edge-on)的视线方向,而就将其视做轮廓边缘,进行描边

  2. 基于过程几何方法的描边

    使用两个pass绘制, 先渲染正向表面( frontfaces),再渲染背向表面( backfaces), 有两种方式让背面可见

    • z-bias : 使用 z 偏置( Biasing)或者其他技术来确保这些线条恰好位于正向表面之前
    • shell method : 背面pass的顶点沿法线偏移 ( 膨胀一下 )
  3. 基于图像处理的描边

    可以将其理解为一种后处理操作。通过寻找相邻 Z 缓冲数值的不连续性,就可以确定大多数轮廓线的位置. 优点是描边的线宽一致,缺点是需要额外的法线和深度信息,当然,由于近年来流行的延迟渲染框架,法线和深度本来就是G-Buffer的一部分,因此往往不需要额外绘制法线和深度的信息

  4. 基于轮廓边缘检测的描边

  5. 混和轮廓描边

  6. 其实还有一种, 就是利用 *模板测试. 也是使用两个pass, 一个正常绘制pass, 然后把绘制区域的模板值 (比如1) 写入到 模板缓冲区 中, 第二个pass先顶点沿法线偏移, 然后对比 模板缓冲区 的值是否为1, 是则不渲染. 这种方式的特显是正常绘制区域内不会有描边效果. 因此也不太适合用于 卡通渲染


可变形状的高光

都采用了这个计算项:

这个halfVec也就是我们常说的半角向量,计算方法是:

其中,L和V分别是光源方向和视线方向。也就是 float3 halfVector = normalize(lightDir + viewDir);