卡通渲染学习总结
技术综合 7390 5
实名

通过了实名认证的内容创造者

发布于 2020-12-17 19:59:39

您需要 登录 才可以下载或查看,没有账号?注册

x
卡通渲染学习总结

文/Reverie

image.png


写在前面

  本着宅男喜欢二次元的初衷,花了不少时间去搜集资料学习卡渲,见过许多新颖有意思的知识,也有一些自己的思考。知乎上不少大佬写过相关文章,但还是想做个总结来记录下收获,顺便也能算是回馈知识。
wiki定义,卡通渲染又称cel shading,泛指通过较少的阴影颜色来代替阴影间的过渡,在21世纪初期常用于渲染赛璐璐风格,便以cel shading命名。时下就表现上来说可以分两种,一种是日式动漫中赛璐璐风格,它的主要特征是颜色鲜明的色块。另一种偏美式,颜色之间的过渡会有渐变,看起来更具真实感。两者主要差距在于Ramp贴图的选择,后者的颜色过渡更加平滑。类似的技术还有素描、油画或水墨画风格。
单纯的卡通渲染作为npr的一项小分支并没有太多发展。比如说GDC2015上著名的罪恶装备中所用上的技术在零几年就已经存在应用了,他们做的是以美术经验为主导的一套技术流,实现的是动漫中很多“反物理”光照表现,吃的还是美术功底。
越是学习卡渲就越能发现它在技术上的极限。近几年慢慢流行的一个方向是将卡渲与pbr结合,譬如说战双、噬血代码和异界锁链。看起来完全不同的两个方向,结合效果反倒还不错。
v2-1253c7ab130de129b424b27fa759fbbe_720w.jpg
1. 角色
角色是卡渲的核心,代表了整个游戏的渲染风格,各家游戏都在这里下足了功夫。
1.1 光影
uts中将光与影分为三种颜色:亮色、一阶暗色和二阶暗色。一个像素的颜色是基于法线n和光照方向l的点积dotNL来控制的。dotNL大于阈值时为亮色,小于阈值时为暗色,根据dotNL值的大小,暗色中还可以再细分为一阶暗色和二阶暗色。
点积结果控制光与影

uts中的光与影

也有许多游戏使用Ramp贴图作查找表取色,这两种做法没有本质区别,只是用Ramp图的好处在于颜色间的过渡更好控制,更适合于表现细腻柔和的插画风格。
硬过渡的Ramp图与软过渡的Ramp图

计算中光影总共只受到三个参数影响:阈值、光照方向和法线方向。要达到理想且可控光影最合适的是从这三个点下手。

1.1.1 阈值
罪恶装备(下文简称ggxx)中使用一个顶点属性通道来存放阈值的offset,控制哪些区域更容易成为阴影,例如下图黑色表示始终为阴影。不过这种使用方式很依赖美术水平,需要他们有对光照点积的理解与把控。
Unity现在提供了PolyBrush,这是一款3D笔刷雕刻软件,有了它可以在编辑器内实时刷顶点色,比起在dcc软件中的效果这一种的好处就是可以看到游戏内实际效果,有个缺陷就是PolyBrush只能导出.asset文件,所以我们要么直接在Unity内将这些个.asset打包为一个Prefab,要么还需要另一个官方包FBX Export来导出为fbx。
ggxx人物阈值offset

ggxx为什么使用顶点属性而不是贴图来存储数据?
虽然常见的是使用贴图,但这也是一个优化的思路,是为了排除像素精度带来的影响。因为采样极度依赖于分辨率,除非是超高分辨率,否则在特写镜头下很容易出现锯齿,而使用顶点属性则会根据屏幕分辨率来插值,达到更清晰的表现。

1.1.2 光照
现在许多游戏中角色材质都有单独的光照方向,这算是一个普遍的做法了,ggxx甚至在过场动画中为了达到最好的效果,会逐帧改变角色的光照方向。
充分了贯彻日式动漫中“相机下的正确才是正义”的理念。
动漫、游戏中光照方向实际不止一个

手游上一般都会有人物专门的展示场景。为了保持最好的光影让角色始终看起来很可爱,这个场景的其实有一些讲究。拿战双举例

人物身上的影子包含两部分,一个是基于nl点积的光影(例如腿部两侧),另一个是来自方向光的投影(图中两个红色箭头)。
先说光影,就是指根据法线和光照方向来计算的阴影,光影方向随着角色旋转会发生变化,就我自己的观察结论,这是一个分段函数:
1.在0-90和270-360之间,始终是从x角度打过来
2.在90-180时,lerp(90, 0, (x-90)/90)
3.在180-270时,lerp(0, -90, (x-180)/90)
x指的是角色旋转的角度,x=0时光在角色的正前方。这样既能让玩家感受到光影存在方向的变化,又能让光始终照在玩家能看到的地方。
另一个是投影。这明显分了两个方向,能看到地上投影的光是从右边打过来,裙子、刀和额发投影是从上方打下来。针对这种有一个兼顾性能与表现的做法,就是裙子、刀这种自投影使用ShadowMap,地上的投影使用平面阴影,毕竟地上大多数情况都是平坦表面,不需要考虑穿模,完美适合高性能的平面阴影,战双是不是这么用的我不清楚,没拆过包。(最开始想到的是用两个ShadowMap,不过这样会多耗一张RT,放手机上其实性能有点勉强)

1.1.3 法线
法线也是控制光照的主要手段,某些角度的光照使得脸部很丑看起来很凌乱,像被虫咬过,例如侧面时的光照。

一种方案是手动调整法线:推特上一位作者提到他最常用的几种方式,(下面三张图)简单来说即通过复制粘贴让某个区域内法线对齐一致,来实现像lowpoly一样的粗略阴影,常见于脸部、手部的法线调整。Yoolies的脸部法线调整教程
另一种是使用类似maya这类dcc软件中的data transfer功能,将圆柱或胶囊体的法线映射到模型上,可以得到平滑的光照效果,常用于衣服、头发上,是一个简单高效的小技巧。
ggxx圆柱法线映射到头发上

自己在blender中尝试了这两种。
理想的效果


尝试结果:原始(左)、手动调整(中)、椭球映射(右)
中间那个想做出眼下三角的感觉,但那个效果不理想,大致感觉是试出来了,这个模型的布线有点差。
除了法线外,还存在一种更加简单粗暴的调整手段:mask遮罩,例如用一个顶点色的通道存储mask,来实现出“鼻子、嘴巴处没阴影”的效果。
mask遮罩调整光影

这种可以理解为就是前面所说的阈值调整,这种方式比起法线调整要直观得多,门槛也低。原神、战双都是用的这种。
然而这种做法也有些限制。一个是网格本身,在眼部和嘴边应该得有这种一圈一圈向外扩大的布线;另一个是法线,毕竟是基于HalfLambert值来进行的调整,而HalfLambert本身就是NdotL,法线如果本身就很平滑的话调整起来会方便很多。

具体实现有兴趣的同学可以看看我关于面部光影调整的另一篇文章
1.1.4 PBR与卡渲
聊聊开头提到的卡渲与PBR,这类做法在霓虹国那边业界已经很熟悉了,至少异度之刃2、噬魂者3就已经有了这种做法,然后传承到噬血代码中,米哈游也一直在探索这个方向,这在以后说不准会成为主流。虽说有PBR,但实际上皮肤还是保持卡通渲染(顶多加个次表面散射),而服装和装备则通过PBR元素来表现质感,不完全是PBR,而是通过一个权重值来与卡渲融合。
下图是噬血代码的渲染流程,他们使用的是延迟渲染,除了GBuffer外还单独扩展一张专门存放数据用的贴图。
(翻译软件+个人理解,可能存在误解)
A:未经后处理的PBR表现
B:BaseMap
C:后处理Bloom图
D:GBuffer扩展图的R通道:表示PBR程度的遮罩,越白则PBR程度越强
E:后处理中计算的光影图,在A图中就可以看到已经算进去了
F:后处理中计算的投影和AO,顺便一提GBuffer扩展图的A通道:投影的落下距离(偏移值),此外G通道是投影的优先级,B通道是用于区分角色、背景等的ID
G:E与F的最小值合成的阴影图
H:PBR高光和后处理高光的合成
I:最终效果,B图中的BaseMap和G中的阴影做乘算,根据参数与H图和C图相加,再根据D图的权重来与A图的PBR进行混合。
可以从D图看到皮肤光影处没有任何PBR权重,就是纯卡渲,并且颜色有渐变的过渡;投影是硬投影;眼睛处有些许pbr权重。
而服装和装备是卡渲和PBR的权重混合,噬血代码和异界锁链PBR都是使用三个通道来控制:金属度、AO和粗糙度/光滑度。间接光部分没有说明,但提到在地图中布有许多probe,猜应该是lightProbe和reflectProbe。
这种算是比较复杂了,其实要表现出PBR感觉,最显著的就是PBR高光:直接高光和间接高光。直接高光选择常见的GGX,间接高光用采样reflectprobe来表现,其实Unity的默认材质那一套就很好。至于间接漫反射光可以看情况选择采样lightprobe,不过漫反射相对而言不明显,根据实际情况决定要不要。

1.2 高光
高光的模型大多是blinn-phone。
spec = pow(dot(n, h) * 0.5 + 0.5, exp2(power));
但头发的高光算法一般是kajiya-kai模型,俗称kk,一层高频,一层低频,再加上一个切线扰动贴图达到各向异性效果。但要想使得高光沿着每根发束移动,还需要美术在头发模型的垂直方向进行uv展开。
其它不那么硬核的方案,例如uts里使用视线空间法线采样matcap贴图做出假高光,法线贴图做出各向异性,加上遮罩图调整出某些位置的渐隐,也能达到不错的效果。
uts头发各向异性高光

这种相似的做法在新樱花大战中也有使用,不过他们的遮罩图是通过uv采样,这样可以精准控制到每根发丝。
E图是uv采样的遮罩


一般除了高光外,大家还会选择叠加一个基于法线n和视线v的菲涅尔边缘光,也就是
用来模拟出反光的感觉,这种光最早有在军团要塞2中提到,他们用来当做在黑暗时的补光手段和用来区分敌我阵营。
然而...动漫里的边缘光和这种边缘光有点不同,动漫中所需要的一般是单向的硬边缘光,而不是后者中这种全方向的菲涅尔边缘光,当然我们可以通过一些手段来让后者变成硬过渡和单向的,UTS里就有做到,不过这有点杀鸡用牛刀的感觉。这种边缘光大家一般还是用来表现特效的多一点。
要达到动漫里的边缘光,一种取巧的方式是用NDotL来计算,这里的L不是场景中的光方向,而是一个自定义的方向光,拿熊熊这张图举例的话,光方向就是在左上方射向右下方的样子,相当于把边缘光当作一般的直接光漫反射计算,做出来效果还挺还原的,更重要的是可控性更好。

1.3 颜色
ggxx里使用了Base Tex和Tine Tex两张贴图来控制颜色。
Base Tex:受光时的颜色
Tine Tex:在阴影中的暗色程度
两者相乘得到暗色颜色。(只是控制暗色的话,在贴图直接画上暗色颜色或许会更方便?一直没想明白这里用乘法的好处)
ggxx的颜色

而在七大罪中使用basemap和matcap来控制人物颜色,缺点是得到的是一个比较固定的光照表现(相机不旋转的话),但好处是可以通过更换matcap贴图来轻松实现不同buffer下的人物特效。
替换matcap来实现buffer特效

由于是手游,牺牲一些光照效果来使用matcap确实是比较实惠的选择,前提是美术能接受的话。
此外,在一些需要将衣服颜色提供给玩家染色的游戏中,就不能再在BaseMap中存入颜色,而应该在着色器中计算,BaseMap仅存放衣服的褶皱之类阴影。
CodeVein的BaseMap

1.4 描边
1.4.1 外描边
一般是back face和后处理描边两种做法。
back face听起来不顺口,大家一般叫外扩法,它的优势:特点是高效、可控性强,一般用于人物、物体的描边。原理就是通过两个Pass来绘制,第一个Pass剔除正面,将顶点沿法线方向小小的扩大一圈;第二个Pass剔除背面正常绘制,经典技术了。
ggxx中还使用到三个顶点属性通道来控制描边。
G:根据相机距离控制描边宽度的系数;
B:描边的z偏移值,一般很大,可以使得一些不想要的描边消失;
A:描边粗细程度,0.5是标准,1是max,0是无;
例如在头发中的应用:调整描边的z偏移去掉不想要的描边

需要注意的是backface的方式需要顶点法线连续,否则在硬边缘的模型上表现会比较差,法线连续的方式一般是将顶点的多个法线取均值,即使用点法线而不是面法线。
Unity法线默认导入方式是面法线,对此的解决方案一种是在ddc类软件中导出点法线贴图,或者是直接做平滑组平滑法线。另一种在导入Unity时使用脚本计算一次点法线并存入模型的顶点属性通道中,后者相对来说更灵活一些,因为可以描边用平滑法线而光源计算依旧用法线贴图。
这中间有一个问题是平滑法线后如何存入fbx文件中?
因为Unity一般只能导出为.asset文件。所以这里可以选择直接在Unity外部用FBX SDK写一个平滑法线的工具,或者是选择平滑法线后用Unity官方的FBX Export插件,这个插件目前还是preview版本,不过够用了。讲道理,我觉得工具放在项目内美术做起来会更舒服一点,而且我们还能自己控制脚本写点批处理UI,所以我选后者。
面法线描边在正方体上是割裂的

另一种是后处理描边:通过检测场景图像中normal和depth的不连续性,效果很好,计算消耗与场景复杂度无关,但问题是无法单独控制描边,会把内描边也绘制出来,而且消耗也不小。属于顶点数量很大时替代backface的做法,适用于场景的描边。例如重力眩晕中人物使用了backface描边,背景用后处理描边。

其实...还有一种,就是高亮描边,比方说求生里的这种。它的原理是用一张RT单独绘制纯色网格,然后对RT做Blur,最后再与原本的颜色图混合。
不过一般用它来做选中的效果,而不会用来做卡渲的描边,虽然它效果不错,也不会把内描边绘制出来,但是它的问题依旧是不好单独控制描边宽度和颜色,而且它是真的那种纯粹的外描边,一点内描边都没有的,太过于适合用来表现轮廓了。
一般我们想要动漫里的效果,应该是网格叠在一块时也会有描边的。
外扩法,手臂在腿部上时依旧有描边
1.4.2 内描边
rtr中细分了很多种的描边,但这篇文章内描边仅仅指的是贴图表面上的线,那内描边有啥说的呢?主要是锯齿,一般贴图上只要存在斜线就一定有锯齿,在镜头拉近时特别明显,因为内描边一般都只有1-2个像素。
1.本村线:为了消除这个锯齿,所有线条都沿轴线对齐,通过改uv的方式来画出清晰线条,因为线条本身是直的,不会有锯齿。但是这么做会得到非常扭曲的uv,不适合图案较多的贴图,感觉正常点的项目都不会选择这么做,因为手工量很大,而且局限也很多限制美术发挥。
他的做法是将内描边使用sdf预计算后单独存放一个通道,也就是通过一种核运算来预计算出贴图上每个像素"距离最近描边"的程度,而根据sdf的性质用这种方式甚至可以控制“较远”的像素的处理方式。
3.基于边缘程度的后处理
二之国中的做法选择在一个顶点属性通道中记录边缘程度,然后在后处理中来进行绘制内描边。
A:绘制外描边后的图
B:存储在顶点属性R通道的边缘程度值
C:存储在顶点属性G通道,基于MeshID指定的面部单位
D:最终效果

1.5 特效
除了matcap外,七大罪也为特效添加专用的光源,让人物与特效有一致的表现。随着手机性能发展,多跑一个光源也慢慢能被主流机型接受了,在战双中能看见不少特效都有点光源。
特效用光源
1.6 其它
1.6.1 眉毛
动漫里一般眉毛是是能够显示在头发上的(反物理+1)。
uts的一种做法是用模板测试,不过这样会多用一张模板贴图,在手机上对带宽不友好。
另一种做法,使用RenderQueue按头发-脸-内眉毛-外眉毛的顺序绘制,眉毛绘制两遍,第一个用ZTest LEqual绘制没被头发挡住的眉毛,第二个用ZTest GEqual绘制盖在头发上的眉毛。眉毛的计算量并不多,这种做法会更省一点。
1.6.2 表情
表情的制作要么就是改模型,要么就是改贴图。
如果对精度没有较高要求、数量也很有限的话,其实直接用贴图就是一种非常实惠的做法,例如>.<这些表情换张图就能很好搞定。贴图的局限性在于动态得通过帧动画的形式来做,数量较多的话还不如改模型。
改模型的做法又可以分为blend shape和改骨骼。
blendshape在CG制作动漫中非常常见,本质是修改网格顶点进行形变预先制作好一套表情组合,像是眨眼之间的表情切换可以通过顶点动画插值来实现。
修改骨骼的变换信息,通过蒙皮来修改脸部模型,就性能上来说这种会好一点。
如果需要表现出一些特殊的漫画中表情,就得考虑为眼睛和眉毛单独建模。
还特殊一点的:颜艺,光影计算已经救不了了,需要另外用贴图来制作,像是褶皱和嘴巴三角阴影,将一些常用小物件(汗、#)放在贴图中,在动画每帧中间插进去,国内基本不会做到这么细致。
1.6.3 眼睛
眼睛能表达的东西很多,根据需求不同,实现方案也有很多种,最简单省事的就是贴图,最多一层baseMap和一层高光足够了,但这放在高品质游戏里难免有点敷衍。
新樱花大战中的做法比较复杂。眼睛的建模实际是两层,外层是向外凸的半透明层,用来绘制高光和反射,表示人眼的角膜;内层微微内凹,表示人眼的虹膜与中心的瞳孔。
C:Albedo Map,基本贴图,表现出人眼的虹膜效果。
D:对基本贴图的加算图
E:高光图,也是通过加法计算,会通过UV动画进行移动
F:环境反射图

2. 后处理
卡渲里对画面提升最大的Bloom和ColorGrading。
2.1 Bloom效果
基本算是必备之一的后处理效果,有没有Bloom那种朦胧感真的不一样。
虽然放手机上带宽消耗挺大的,但是效果着实不错,Bloom实现的相关文章很多就不多说了,去Unity的PostProcess(PP)包看看源码都可以。
左图开了Bloom,右图没开2.2 ColorGrading
调色绝对算得上是最神奇的后处理效果了。它一般有两种使用方式。
1.用查找表LUT来进行颜色转换
LUT表可以由美术在PS里生成并导出,可以做出昼夜黄昏效果,什么新海诚风格、日式风格都可以。它原本就是摄影领域的产物,各种大片感都能做,难点在于调色也是一门学问(电影还有调色师呢)。它的原理是通过rgb通道值作为采样坐标从查找表中查找并返回一个新的颜色。不同的LUT可以不同的画面整体颜色。(需要注意大概就是提供给美术的测试图的颜色空间需要和计算时一致,在Unity PP中为了导出的测试图具有更大的色域,计算前会先转到ALEXA LogC空间)
例如昼夜黄昏。
2.在引擎内实时调整反馈
这种其实和在PS里原理是一样,不过PS能导出一整张LUT,这种则封装在引擎内可以实时调整。一般颜色调整分为大致两个步骤:
Color Grading:画面整体调色
ToneMapper:将HDR颜色映射到LDR范围
Color Grading又分了很多小项:Post Exposure、Contrast等,建议看看catlike这篇文章
原理讲得很清楚,一看就懂(误)。不过就算明白了原理,但是要做出还不错的效果还是挺不容易的。

2.3 色散效果
这在动作游戏见到比较多,增强击中感,常和径向模糊配套出现,不算常用,仅仅记录一下。
原理上挺简单,就是对不同颜色通道值使用不同的uv偏移值来采样,这里是rg通道,并且根据像素离屏幕中心的距离远近会有不同的偏移值。
后处理的其它类别太多了,就不细说,类似的文章也很多。

3. 有意思的技巧
Fake Interior
用CubeMap和一个正方体实现假的“室内”效果,我觉得挺有趣的,于是做了一个实现。
Reverie:一种假室内(Fake Interior)效果的实现&#8203;zhuanlan.zhihu.com
mposter Animation
对大量的npc使用面片播放帧动画代替实际人物模型,而这些图片是由多个相机对3D模型预计算生成图集所得,实际游戏中根据视线角度和关键帧来显示子图。
又是一个能省下来计算量的做法,况且这些面片还可以合批。
不过用它做动画的问题在于每一帧就需要一张图,要保证精度,一张图至少得要512分辨率,一个帧动画少说都有5、6帧,这么多贴图放shader里难免对带宽有点吃力,这种还是只做静物就行,大批量的房屋比较合适。
这个效果我也在Unity做了一个初版,基本和视频中一致。
Imposter伪装者效果&#8203;github.com
顶点运动模糊
通过移动顶点位置来实现的运动模糊,简单高效,但要调整出好看的效果估计得加个遮罩。这个也有人实现过一遍。
AnimMap
本质上是一种顶点动画,通过贴图记录下每个关键帧的顶点位置,比方说6*1024的贴图,6表示6个关键帧,1024记录1024个顶点的位置,结合GPUInstance,达到高性能且不错的表现,非常适合大批量路人、观众这种,可以弥补imposter的不足。
陈嘉栋:利用GPU实现大规模动画角色的渲染&#8203;zhuanlan.zhihu.com
4. 最后
我准备这篇文章花了不少精力,最初只是想找一下法线的调整手段,不知觉间就越找越多,就萌生了整理的想法。文章写了这么长,但其实还有很多很多其它值得研究的方向和细节,个人水平有限而且暂时也没更多的精力研究,不误导人所以没有放在这,隔壁岛国在这个领域是王者,不仅仅游戏,他们不少动漫也使用CG的方式来做,相比国内有太过丰富的经验。本文中的技术方案有不少,但终究应用到项目中满足需求还是只能提供一个思路,没有实现,或许需要踩上不少的坑。

参考资料
5. CGWorld历年杂志


END


v2-94bd2102b421b49759b6875193598a76_180x120.jpg

评分

参与人数 2活跃度 +40 展开 理由
愚不是渔... + 20 技术贴呀
Zorron + 20 【诚意】很有诚意的内容,获取额外奖励

查看全部评分

天若有情天亦老, 人间正道是沧桑。
使用道具 <
一色彩羽大胜利  发表于 2020-12-21 17:38:34  
2#
很厉害,受教了
回复 收起回复
使用道具
diditimes  发表于 2021-2-4 21:00:30  
3#
很厉害
回复 收起回复
使用道具
台笑大方  发表于 2021-2-5 17:41:59  
4#
收藏慢慢学习。
回复 收起回复
使用道具
兽捕鸟了  发表于 2021-3-17 10:37:12  
5#
好东西 学习啦
回复 收起回复
使用道具
棋子  发表于 2021-4-9 18:05:46  
6#
太厉害太详细了!!
回复 收起回复
使用道具
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表