3D日式卡通人物渲染的经验分享

发表于2015-04-29
评论2 2.67w浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594

卡通渲染虽然已经是个比较成熟的技术并且已经在许多游戏中得到了成功的应用,但相关资料比较零散,并且针对3D日式卡通人物渲染的技术文章较少,内容也不太详实。在开发项目中我们查阅、整理并总结了很多相关的paper,包括从90年代的关于Cel Shading的早期研究【10】【15】,到近期的NPR渲染技术【9】【11】【12】,分析了各种渲染技术的优缺点、适用性,最后得出了质量和性能都比较满意的方案。尽管项目仍在开发中,所用的技术仍有很多改进的空间,但我们希望通过此经验分享能够抛砖引玉,或对有需要的人有所帮助,少踩些坑。

图1.卡通人物渲染图,注意并非最终Joker Game游戏成品图

 

卡通渲染本质上是一种非真实渲染技术,其效果的好坏并不像真实渲染一样有一个物理真实的参考标准,感性的成分比较大,因此我们认为要做好的关键是尽量少做假设和“硬编码”参数,从而给美术提供足够的自由度以实现其想要的效果。

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

l        勾边

l        梯度漫反射(Ramped Diffuse)

l        头发高光

l        边缘光

l        阴影和面部补光

下面将逐一详细介绍每个子效果的作用和实现方式。
勾边

有无勾边通常是一副画像给人予是否卡通风格的关键提示,显然勾边的效果好坏是非常重要的。 我们在处理勾边问题上主要遇到了三个重要的挑战:

l        抗锯齿

l        灵活性

l        高效率

勾边的锯齿在卡通渲染中会显得尤其碍眼,特别是当角色运动时,带锯齿的勾边会出现非常严重的闪烁问题。因此如果抗锯齿不解决的话,即使其它效果非常好也会大打折扣。

 

勾边的算法一般分为Image-based、Object-based以及传统的Two Pass等三种【1】【2】【6】【7】

Image-based的算法是通过在图像空间上分析depth和/或nomral的连续性来决定一个像素是否为物体的边缘的。它的优点是算法复杂度跟场景几何无关,只跟画面大小有关,并且对于带有镂空贴图的物体不需额外的开销也能正确处理,而其缺点则是生成出来的勾边锯齿很难消除,并且勾边的粗细和有无难以控制。

图2. Image-based勾边算法,(a)深度图.(b)深度图勾边.(c)法线图.(d)法线图勾边

 

Object-based的算法一般是通过对物体的多边形进行动态分析来决定轮廓边的。由于一条边是否为轮廓边取决于其相对于观察者的视角,所以这意味着轮廓边每帧都必须重新算,这开销是非常大的,即时有的算法做了很大的优化【8】。但优点是可以保留很多细节的勾边,锯齿也比较好解决(通过MSAA),并且对不同的物体可以分别控制勾边的粗细和有无,甚至可以有各种线条化风格【5】

图3.基于Object-based的风格化勾边效果【5】


对于勾边,其实一种更传统的做法是Two Pass渲染:对每个物体渲染两次,第一次画背面,使用线框模式或按法线方向放大一点;第二次则正常画物体。这种方式虽然在数学上严格来说是不正确的,生成出来的并不一定是轮廓边,很多真正有效的轮廓边也会被遗漏,如图4所示,但由于实现简单,效率也高,对硬件友好,因此反而是实际中经常被用到的,例如MMD。

图4.(a)Two Pass方法造成部分轮廓边丢失.(b)完整的轮廓边

 

在综合考虑之下,我们选择了基于传统的Two Pass + Object-based的混合方法来实现勾边效果。大概的思路是使用Two Pass方法来绘制普通勾边,而细节勾边则由Object-based的方法来绘制,另外使用一张勾边的蒙图来解决镂空和半透明部分的问题。这里所谓的细节勾边是指Mesh内部的凸起和凹陷部分的线条,并不包括随视角改变的轮廓边,因此细节勾边可以在Mesh初始化时通过静态分析多边形来生成:如果一条边所相邻的面的法线朝向之差大于某个阀值,则判定它为细节勾边。

图5.(a)正常渲染.(b)普通勾边.(c)细节勾边.(d)完整效果

 

勾边的粗细可以通过这样来调节:对于普通勾边,通过调节画背面物体时的扩大程度来决定,这是个可以在Vertex Shader里调节的参数;对于细节勾边,如果画的Primitive是LineList,则是设置图形API的线宽,并根据物体到视点的距离来调节其粗细,如果图形API不支持设置线宽的话,例如D3D,则可使用Billboard Quads来代替LineList,其宽度生成时即可决定。

这样一来,我们既能保证勾边效果的细节程度,又不会给性能带来过多的开销。

但是细节勾边也带了另外一个问题,即多余的边,如图6(a)所示,因此我们需要一种方法来让美术同事来方便地指定哪些勾边是想要的,哪些是多余的,并且能控制勾边的透明度,以便能实现勾边和本体的自然融合过渡的效果,如图7(a)所示。

图6.(a)多余的勾边.(b)使用Mask蒙图去掉多余的勾边

图7.(a)自然融合的勾边.(b)不自然融合的勾边

 

我们使用了一张Mask贴图来控制勾边的透明度,这张Mask贴图和Diffuse贴图的UV空间是一致的,默认为全白,即所有勾边都可见,美术只要把不需要勾边的部位调成黑色即可。

使用这种勾边方案的好处是只需要打开MSAA即可解决锯齿问题,通过Mask蒙图可以灵活地控制每个物体的勾边细节和透明度,又不需对现有的渲染管线做太大的修改,兼容性和效率都比较高。


梯度漫反射(Ramped Diffuse)

传统的漫反射系数函数是一个连续的线性函数,而所谓的梯度漫反射则是对其再做一次映射变换,其中的函数其实就包含在一张一维的纹理里。

美术通过控制该图片里颜色的梯度来实现梯度漫反射效果

图8.越柔滑的Ramp图生成的漫反射越柔滑

采样后的梯度颜色会和材质的漫反射颜色相乘,最终的漫反射颜色为:

可见当时,梯度漫反射即为传统的漫反射。需要注意的是我们使用的是LDR光照,因此漫反射系数会被之间。如果你需要使用HDR光照,我们建议梯度漫反射最好在Tone Mapping之后进行,以取得最好的效果。

这个模型非常简单,在实现上也是数条指令的事情,但却很有效。

最后,值得一提的是这个思路可以扩展到考虑除漫反射系数之外的其它因子:

例如高光系数等,对应的函数则为一张二维或更高的纹理。这样可以实现更丰富的效果,但同时也会增加美术的工作量,因为人工来生成这样的一张纹理是不容易的。

纹理尺寸大小的选择上,尽管可以使用16x1甚至更小的尺寸,但我们使用的是16x16大小,以便于直接观察,而实际的性能开销区别几乎没有。


头发高光

日式卡通人物的一大特点就是头发高光,这些高光的形状以及颜色过渡都有不同的风格,但共同的特点都是条状形的。假如没有这些高光的点缀,那么卡通人物就会顿时显得平淡无味,因此头发高光做得好与坏对整体效果的影响也是非常大的。

区别于普通高光,头发高光是各向异性的,它的形状通常是跟发丝伸展的方向正交并呈条状延伸,并会随着头发的纹路而出现波动效果(Zigzag),而跟场景灯光的位置并没有多大关系。在详细介绍我们的卡通头发高光算法前,先简要介绍下真实的头发模型以及非卡通的头发高光渲染方法。

文献【4】中提到,现实中的一根头发形状近似一条可弯曲的圆柱体,其表面并不光滑。对于单跟头发而言,如果我们定义其切线方向为从发根到发丝的方向,取其横切面为法线平面的话,那么给定一光线入射角,其各个方向的反射强度大致是这样的:

图9.真实头发的在45度入射光线下的反射强度图【4】

从图中可以看出除了主反射外,还有副反射,并且反射的方向并不是严格等于入射光的反射方向。

由于头发大部分是一根根并排排列的,所以当许多根头发集合在一起时,其总体的高光反射就会呈现出这样颜色层次丰富的条状效果:

图10.真实头发【4】

尽管理论上我们可以将从真实头发上采集来的反射图数据编码到一张二维纹理中,然后渲染时对其采样来获得当前光照方向和视角方向下的反射系数,以获得更精确的效果,但实际上可使用一个更简单的近似模型【3】,假设为当前点到光源方向,为当前点到视点方向,为头发的切线方向(从发根到末端),为头发的光泽度,则最终的高光强度系数可这样计算:

为了模拟主高光和副高光,可以对切线分别朝法线方向做两次不同程度的偏移,然后计算后相加【3】

对切线朝法线方向做偏移会使高光的位置也跟着偏移,因此如果对每个当前点的切线都做这种扰动的话,那么就会有Zigzag波动效果了:

图11.不同扰动程度下的头发高光(仅有主高光)

我们使用了一张灰度图来描述头发上每个点的切线的偏移量,这张图的UV空间和Diffuse贴图是一致的。

图12.头发高光扰动图【3】

最后,要实现卡通风格的头发高光效果,只需要加一步类似梯度漫反射里的方法即可:

这样,美术就可以通过控制一张高光的Ramp图片来决定高光带过渡的柔和度了。

图13.不同高光Ramp函数下的头发高光

如果你需要副高光,那么建议使用两张不同的Ramp图片来分别控制主副高光的过渡。我们还使用了一张高光Mask贴图来控制哪些部分是需要高光的,并且可控制高光的颜色。

另外,需要注意的是,对于高光,我们使用的光源方向并不是场景中的光源方向,而是一个虚拟的光源,此光源的方向也可由美术控制以调整高光的位置。


边缘光

除了头发高光外,我们并没有实现普通的高光,而是实现了边缘光。边缘光通常出现在皮肤和较透彻的服饰的边缘处,这是因为光线会透过这些介质并在介面处发生多次反射折射最终到达观察者的眼中。实际上我们无法准确模拟这样复杂的过程,只能近似这种效果。

事实上无论反射和折射都可用菲涅尔方程来描述,该方程可描述给定一介面和其上一条光线的入射角后,反射和折射光线的量。概括地说,当光线越垂直于介面,则折射量越大,反射量越小;当光线越平行于介面,则反射量越大,折射量越小。在实际游戏里,常用以下方法来模拟菲涅尔反射量和折射量

其中,为介面法线,为当前点到视点的方向,分别为反射和折射的系数。

对于卡通人物来说,我们只需要取其反射项即可,并给一定的偏移量以模拟边缘光的宽度,效果如图所示。

图14.边缘光


阴影和面部补光

除了上述的各种效果外,阴影和面部补光也是个非常重要的问题。阴影的重要性就不言而喻了,而面部补光则是一个针对面部阴影问题的特殊光源,之所以需要它是因为人们通常对卡通人物的面部敏感度非常高,一些不想要的阴影投射在嘴角等处会对人物的表情造成极大的影响【13】【14】,这就是面部补光要解决的问题了。

对于每个物体,它都可以有一张阴影蒙图来描述哪些部位是需要接受阴影的,默认为全白,即都接受,美术只需把不想要阴影的地方调成黑色即可,阴影蒙图的UV空间也是和Diffuse贴图一致的。

而当一个部位不接受阴影时,那么它通常是需要补光的,补光的照射方向总是从观察者到物体的方向,就好象观察者的头上戴着个探照灯一样,其强度可由一个参数控制。

图15.(a)没有面部补光.(b)有面部补光

组合起来

上文已分别详细介绍了各个子效果的作用和算法,现在讲介绍一下如何将它们组合起来,得到最终效果的。

对于每个需要卡通渲染的物体,首先使用ToonShading的Shader正常渲染一遍,得到带有梯度漫反射、头发高光以及边缘光效果的结果,然后开启AlphaBlend来渲染普通和细节勾边,使用的是另外的Outline Shader。

在ToonShading时,要求场景需要有一个方向光主光源,用来生成阴影和梯度漫反射,注意阴影同时也会影响头发高光和边缘光的强度。

最终颜色值的融合非常简单:


编辑工具

正如前面所提到的,我们认为卡通渲染效果要做好的关键是要提供给美术足够的自由度,所使用的算法、数学模型等并不会也不需要很复杂,但一定需要高度的灵活性和可自定义性,让美术能在此框架下做出不同风格化的效果。编辑工具的设计也遵循这个原则,暴露出刚好足够的参数让美术去调整,参数太少能控制的效果范围也小,而参数太多则会出现功能冗余而令人产生费解,容易失控并很可能出现Bug。

对于美术来说,卡通效果只是另外一种材质而已,我们提供给美术的编辑工具其实就是一个卡通材质的编辑器,介面如图所示:

图16.卡通材质编辑面板

我们还为美术提供了较详尽的说明文档,这样可以避免很多重复交流沟通的成本,同时也给我们开发者自己以后作为备忘和参考。

值得一提的是,为了能让美术在修改各个纹理贴图后能即时看到结果,我们实现了纹理资源的热加载,美术只需要在PS里保存修改后的贴图后即可在编辑器里看到效果,这对开发效率帮助很大,正所谓工欲善其事,必先利其器。其实,在开发ToonShading的Shader过程中,我们也实现了Shader的热加载功能,这对调试Shader也是有极大帮助的。


性能分析

我们针对的最低图形硬件规格如下:

l        桌面平台上支持OpenGL 2.1,Nvidia GeForce 6600级别的显卡

l        移动平台上支持OpenGL ES 2.0,iPhone4级别的硬件

虽然整个游戏运行时的帧率和内存使用量取决于很多因素,但无论在哪个平台上卡通渲染本身并不应该成为整个渲染管线的瓶颈。

我们的卡通渲染方案对性能的影响因素主要有两个:

l        画勾边时的两次Pass,包括一次画普通勾边的Pass,和一次画细节勾边的Pass。其中普通勾边使用的几何和正常渲染时用的原几何相同;细节勾边基于原几何生成,其复杂度通常不会比原几何更复杂,且只需在初始化时生成一次。勾边的Shader非常简单,编译后的静态指令条数只有23条,其中只有1次Texture Fetch用于采样勾边蒙图,使用GPU ShaderAnalyzer分析后的结果如下,注意即便在最低端的HD 2400显卡上也只需要7个cycles:

l        ToonShading Pass。这是卡通渲染的主Pass,也是主要的性能开销所在。为了更准确地测试ToonShading的开销,我们在测试过程中屏蔽了阴影。该Pass总共需要4次Texture Fetch,分别是用于采样:Diffuse、Ramp、Specular Mask、Shadow Mask贴图。在中低端显卡上这个Pass的瓶颈在算术指令上,而在高端显卡上的瓶颈则是纹理采样指令。编译后的静态指令条数为122条,GPU ShaderAnalyzer的结果如下:

 

在目前实际的游戏场景中,卡通渲染的性能测试结果如下表所示:

Nvidia GeForce GTX 560 Ti+Intel Core i7 2600@3.4GHz+8GM RAM+Windows 7 64bit

无勾边、无阴影、仅人物

1.429ms

加入勾边

1.553ms

加入阴影

2.381ms

完整场景

5.025ms

可见,卡通渲染在整个渲染管线中目前并不是瓶颈所在,特别是在把阴影关闭的情况下,渲染带骨骼动画的卡通人物总耗时小于2ms。另外,由于移动平台上的版本正在开发调试中,因此暂时并没有相关的性能测试数据。


总结

本文简要地介绍了卡通人物渲染的相关技术以及我们在Joker Game里的解决方案。由于Joker Game仍在开发中,本文所介绍的卡通渲染的技术也还有很多改进的空间,许多小细节也还阐述得不太透彻,感兴趣的同学欢迎随时来交流,本文仅做引玉之砖,希望能对卡通渲染入门的同学有所帮助。

 

参考资料

【1】A survey of silhouette detection techniques for non-photorealistic rendering. Wang Ao-yu, Tang Min, Dong Jin-xiang. Zhejiang University.

【2】Introduction to 3D Non-Photorealistic Rendering: Silhouettes and Outlines. Aaron Hertzmann. Media Research Laboratory. Department of Computer Science.

【3】Practical Real-Time Hair. Renderingand Shading. Thorsten Scheuermann. ATI Research, Inc.

【4】Light Scattering from Human Hair Fibers. Stephen R. Marschner. Cornell University.

【5】Artistic Silhouettes: A Hybrid Approach. J.D. Northrup and Lee Markosian. Brown University.

【6】Silhouette Extraction. Bruce Gooch, University of Utah.

【7】Cartoon Style Rendering. Simon M. Danner. Christoph J. Winklhofer†.

【8】Fast 3D Cartoon Rendering with Improved Quality by. Exploiting Graphics Hardware. Johan Claes†, Fabian Di Fiore‡, Gert Vansichem‡, Frank Van Reeth‡.

【9】State of the Art Non-Photorealistic Rendering (NPR) Techniques. Rezwan Sayeed and Toby Howard, School of Computer Science, The University of Manchester.

【10】Cartoon Rendering of 3D Scenes, Cel Shading. Philippe Decaudin.

【11】Non-photorealistic Rendering. http://gfx.cs.princeton.edu/proj/sg05lines/course7-4-npr.pdf

【12】Non-photorealistic Rendering. http://www.cs.utah.edu/npr/

【13】偶像大师 2 - 《全面升级偶像们的表演》.http://www.opengpu.org

【14】第 3 期  [CEDEC 2010][次世代的偶像大师].http://www.opengpu.org

【15】Cel Shading. http://en.wikipedia.org/wiki/Cel_shading

 

本文作者: zaneli(李镇)

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

游戏学院公众号二维码
腾讯游戏学院
微信公众号

提供更专业的游戏知识学习平台