卡通渲染技术总结

卡通渲染技术总结

卡通渲染是一种非真实感的渲染技术(NPR),可以使生成的图像呈现出手绘般的效果。广义的卡通渲染技术有很多,本文介绍的主要是日系卡通的渲染技术。

1 轮廓线

参考《Real-Time Rendering》,卡通渲染中的轮廓线有以下几种:

(1)Boundary or border edge:仅为1个多边形所拥有的边界。封闭模型一般不具有这样的边界;

(2)Crease or hard edge:为2个多边形共有的边界,而且2个多边形的夹角(dihedral angle)大于一个阈值。这个阈值的参考值为60度;

(3)Material edge:不同材质的2个多边形的公共边界,或者是人为期望显示的边界;

(4)Silhouette edge:相对于当前观察方向而言,面向不同朝向的2个多边形的公共边界。

1.1 点乘法(Surface Angle Silhouette)

基本思想是利用viewpoint的方向和surface normal的点乘结果得到轮廓线信息。这个值越接近0,说明离轮廓线越近。计算方法如下:

half edge = saturate(dot (normal, viewDir));
edge = edge < threshold ? edge/4 : 1;

由于这种方法渲染的轮廓线宽度不均,实际应用不多。

参考资料:

【Unity Shader实战】卡通风格的Shader(一) blog.csdn.net/candycat1

在Unity进行水墨风3D渲染的尝试 zhuanlan.zhihu.com/p/25

1.2 背面扩张法(Procedural Geometry Silhouetting)

这种技术的核心是用两个pass渲染。第一个pass中正常渲染frontfaces,第二个pass中在渲染backfaces,并使用某些技术来让它的轮廓可见。

常用的方法是,在顶点着色器把backface的顶点沿着顶点法向方向向外扩张,使其包裹原有的模型。

这种方法的优点是,不需要任何关于相邻顶点/边等信息,所有的处理都是独立的,渲染速度很快,而且线条宽度可控,有一定的健壮性。

缺点是:

一,像cube这样的模型,它的同一个顶点在不同面上具有不同的顶点法向,所以向外扩张后会形成一个gap,如下图所示。

一种解决方法是强迫同一个位置的顶点具有相同的法线朝向。另一种解决方法是在这些轮廓处创建额外的网格结构。由于gap大多在模型放大的情况出现,根据到Camera的距离控制轮廓线的宽度,一定程度上可以减少gap的出现。

二,这种方法渲染的backfaces有可能与原有的模型在深度上发生冲突,并且遮挡模型,如下图所示:

一种解决方法是给backfaces设置Z-offset,使轮廓线埋没到临近的面里。另一种解决方法是修改backfaces扩张的法线,使轮廓线扁平化。

参考资料:

【Unity Shader实战】卡通风格的Shader(二) blog.csdn.net/candycat1

Silhouette-Outlined Diffuse wiki.unity3d.com/index.

总结:

上述方法都有一个共同的缺点,那就是对轮廓线的外观可控性很少,而且如果如果场景上的物体都需要绘制轮廓线,每个物体都会增加一个draw call,性能上的开销会比较大。

此外,背面法只能渲染Silhouette edge,不能渲染Crease Edge和Material Edge。

1.3 屏幕后处理法(Silhouetting by Image Processing)

这种技术利用了G-buffer,在每个buffer中使用了图像处理的技术来检测轮廓信息。

基本思想是,利用图像处理中的一些算法,在Z-buffer中找到不连续地方,由此计算出大致的轮廓线。还可以在surface normal中找到不连续点,来获取更完整的轮廓线。最后还可以在ambient colors中,进一步完备前两步找到的轮廓线信息。

因此,基本步骤是:

1. 使用vertex shader把world space normals和z-depths渲染到纹理中。

2. 使用一些滤波算法来找到边缘信息。一种常见的滤波算子是Sobel边缘检测算子。

3. 找到边缘后,我们还可以使用一些图像处理操作,例如腐蚀和膨胀,来扩展或者缩小轮廓线宽度。

这种方法的优点在于:

(1)适用于任何种类的模型,而且不需要CPU参与创建和传递一些边的信息。

(2)可以渲染Crease Edge,而且可以设置阈值,控制Crease Edge的采样。

但也有它的缺点:

(1)这种对z-depth比较来检测边界的方法,会受z变化范围的影响,一些z变化很小的轮廓,比如桌子上的纸张,就无法检测出来。

(2)轮廓线的宽度不能根据物体单独控制,而且不能区分Silhouette edge和Crease Edge。

1.4 实际案例

对于角色,大部分游戏中的轮廓线都是用背面沿法线向外扩张的方法实现的。而且很多游戏还在此基础上做了轮廓线的风格化处理。例如,《罪恶装备》大量使用了顶点色控制轮廓线的风格:

R通道:控制光照的明暗变化

G通道:控制顶点根据视距膨胀的强度

B通道:控制z-bias,值越大轮廓线越靠后

A通道:控制轮廓线的粗细

对于一些特殊的分镜,可以使用更复杂的轮廓线制作方法。在《火影忍者疾风传》中,使用了判断轮廓线的RenderTexture,一次进行两种方法的绘制。还加入了可以给角色分别指定颜色的【ID Buffer】,用4X4的16像素Texture保存颜色信息,再取得颜色来绘制角色的轮廓线。另外也可以追加Glare的信息,制作出角色轮廓的自发光。

参考: gad.qq.com/article/deta

2 着色

卡通渲染的着色主要包括阴影、高光、边缘光和内轮廓线(主要是角色身上细碎的线条,区别于上文的外轮廓线,类似于Material edge)等要素。

2.1 原理

卡通渲染的阴影不同于一般意义上的阴影,而是拆分成了两个更精细的定义:

阴:很难被光照射到的暗面,即背对光源的区域

影:由其他物体遮挡生成的暗面

(1)阴

物理上的漫反射是用dot(N,L)模拟。卡通渲染的漫反射是一个阶梯函数(step function),直接将光照分为明暗两部分,用一个阈值(Threshold)映射dot(N, L)。

实际使用时,可以用smoothstep代替step,并增加一个参数控制暗面与亮面的过渡平滑程度,一个参数控制亮面与暗面的过渡位置。


代码:

half NdotL = dot(N, L) * 0.5 + 0.5;

half diff = min(NdotL, attenuation); // attenuation为shadowmap计算的阴影

half diffuseMin = saturate(_DiffuseCutLocation - _DiffuseCutSmoothness);

half diffuseMax = saturate(_DiffuseCutLocation + _DiffuseCutSmoothness);

half diffuseColor = smoothstep(diffuseMin, diffuseMax, diff) * col;

不同smoothness的效果:

(左)偏于2D动画的风格,(右)偏于3D写实的风格

函数可以是两段也可以是多段。

也可以用Ramp Map代替函数。多组ramp可以组合在一起,供美术自由切换。

因为光照的计算用了step function,明暗界线对于法线非常敏感,尤其是脸部,很容易产生不平整的界线,影响模型的美观。

而且,法线对轮廓线描边的影响也很大,所以卡通渲染的模型必须人工调整法线。

修改前的效果:

修改后的效果:

可以使用的模型法线修改工具:

(1)UserNormalTranslator (SoftImage XSI)

(2)NormalPainter (Unity)

(3)NormalThief (Max)

因为修改过顶点法线的模型不能直接使用法线贴图,所以如果需要使用法线贴图,最好把修改过的顶点法线存在顶点色或者UV上,这样不影响其他效果的使用。

2)影

实际制作中,会希望阴影有一定的倾向,即有些地方容易产生阴影,有些地方则很难产生阴影。

比如,凹陷的地方和受周围遮挡的地方应该被认为是影,需要增加阴影倾向,改变光照表现。

这时候可以用一张贴图或者顶点色控制阴影的倾向,对上面的映射函数进行偏移。

没有阴影倾向的效果:

有阴影倾向的效果:

但是,阴影倾向信息不能反映外部遮挡物投射的阴影,最好结合shadowmap一起使用。

(3)高光

高光、边缘光的处理方法和漫反射的映射类似,也是用step function控制明暗。

如果是金属或者其他特殊材质,需要保留更多的高光细节,可以和Blinn-Phong或者GGX光照模型混用。

不同材质的边缘光最好用mask精确区分:

盔甲上没有边缘光:

盔甲上有边缘光:

(4)内轮廓线

材质上的轮廓线只能在贴图上绘制。但是,由于精度问题,贴图上的线放大会出现锯齿。

《罪恶装备》使用了一种叫本村线的方法,即扭曲UV,只用垂直线和水平线构成贴图。

但是,这种方法有个缺点,就是会扭曲贴图上的文字和花纹。所以,《罪恶装备》的角色都是用的纯色贴图,一些带有文字的区域都做成贴花,用新的mesh附在模型上。

无内轮廓线:

有内轮廓线:

2.2 制作流程

以罪恶装备为例,shader主要用到3张贴图:main tex, ilm map, sss map

(1)main tex:固有色

(2)ilm map:用于调整阴影和高光区域的形状

R通道:

底色为128灰色,可以理解成材质的光泽度,控制高光的强弱。

材质越粗糙,灰度越小;材质越光滑,灰度越大。

G通道:

底色为128灰色,表示阴影的倾向,控制阴影区域的大小。

容易产生阴影的区域(可以理解成有自投影的区域)灰度较小,如脖子、腋下、鼻子下方、衣服的褶皱、头发遮住脸部的部分。

B通道:

底色为黑色,控制高光区域的大小。

A通道:

底色为白色,表示内轮廓线,贴图上的线条需要拉成横线和竖线,否则会有像素锯齿。

(3)sss map:用于调整阴影的颜色

亮部颜色 = mainTex

暗部颜色 = mainTex * sssMap

3 参考资料

[1] GuiltyGearXrd's Art Style : The X Factor Between 2D and 3D

[2] 罪恶装备 Xrd REVELATOR 3D进化出的非照片真实视觉

编辑于 2019-10-15 11:47