
文丨Mr_ctong
腾讯互动娱乐 工程师
导语:
在游戏制作中,人物的占比越来越大而且已经成为一个体系。渲染和优化的时候都会为角色量身定制一套方案。甚至为了角色表现,会为展示在大厅的角色单独做一套效果和资源。本篇主要从角色渲染中最难的头发渲染开始说起。本人水平有限,如有错误,请不吝赐教。
大纲

头发模型
科普一下实时渲染和离线渲染的区别。
实时渲染:计算机需要在运行时生成所有的3D模型、贴图等等,并以尽可能快的速度(每秒30帧以上)显示给用户。
离线渲染:是将每帧的画面渲染成图像格式,然后将静止的图像或图像序列(1秒24帧)合成,转变为你所看到的动态画面。
实时基于线的头发渲染是困难的:
1. 发丝数量多,人体一般有8W~13W根头发
2. 头发种类繁多,形式多样,不同颜色的头发对光线的吸收不同
3. 在角色渲染中,复杂的头发渲染可能占用角色25%左右的渲染时间
所以在手游中,基于线的头发渲染是不现实的。目前主流的hairwork也是把头发变成面片模型。


注:针对目前硬件设备(手机)水平,如果要逐发丝渲染,开销过大,采用模型分块绘制是一种在效率和效果之间寻求的一种妥协方案。
手游制作头发主要分以下2步骤:
1. Maya的XGen等工具制作头发模型和贴图(美术工作)
2. 应用游戏引擎的Shader来渲染(TA和程序工作)
头发模型和贴图的制作(美术)
这一部分主要是美术来完成,对最终成品有至关重要的影响!
对制作流程感兴趣的可以参考XGen学习路径:
https://knowledge.autodesk.com/zh-hans/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2018/CHS/Maya-CharEffEnvBuild/files/GUID-C0470142-600B-4615-8110-EC779934DF5F-htm.html
注:
1.制作人物角色部件之前,最好统一单位大小,Maya通常是厘米cm,3dMAX通常是英寸inch,Unity则是米m。建议使用现实世界物体的尺寸,因为这样会影响光照的计算、物理效果模拟等与现实世界相关的功能。
2.maya或3dMax中用Stingray PBS材质制作的效果,可以原汁原味的还原到Unity2018.1以上的版本中(用StandardShader)
3.正方向对齐。Unity是左手坐标系,3dMax是右手坐标系,导入后要旋转个180度挺不方便的,建议美术制作过程中就以Unity中的坐标系为基础。
一般的,模型和贴图有写实与非写实区分,从卡通到写实的表现如下:



根据不同的发型定位一般有不同的制作方式:

基于网格制作
如果是制作偏卡通向的发型,可以直接操作网格的点、线、面来制作。卡通效果的头发可以是一坨坨的(如下图),即使丢失一些发丝间的细节也不会有太大影响,美术师逐一制作组成头发即可。
这种方式虽然比较传统,但胜在简单,适合用来制作卡通风格的头发。

基于引导线制作
如果要制作偏写实的头发,就需要更细致的调整,需要发丝间的穿插细节(Noise)和更多的发丝点缀。

使用XGen可以基于引导线自动生成头发,可以轻易的调整头发的疏密,厚度等,美术大大需在此基础上进一步做后期处理“造型”,最后将这曲线转为面片输出给程序。
这种方式适合用来做任何情况的头发,特别是在偏写实的情况下比直接操作Mesh更高效。大体步骤如下:
1.首先绘制引导线,进行简单的造型

2.通过XGen工具来生成头发

3.美术师进一步通过工具造型,并转为面片输出给程序

头发贴图
比较常用的头发贴图有下面几种:
Albedo:漫反射贴图
和Color一起组成最终头发的漫反射颜色。是头发渲染中不可或缺的贴图。

Normal Map:法线贴图
给模型提供更多的细节,一般是由高模渲染导出,在低模中使用,使低模在面数不足的情况下,依然保留高模的表面细节。一般来说也是不可或缺的。

AO(Ambient Occlusion) Map:环境光遮蔽贴图
增加发丝间阴影,完善的遮蔽细节,提升头发整体的体积感。非硬核写实游戏可以不关注,大部分游戏在开启自阴影后也能达到不错效果。

Shift Map:偏移贴图
用来模拟各项异性高光的“锯齿”效果。但目前而言,我看到的更多的实现方式是通过修改切线在法线方向上面偏移来计算实现。而不是读取贴图。


Transparency Map:透明贴图
可以简单理解为漫反射贴图的灰度化后的加工图。本质是做一个mask。增强发丝感。

Ramp Map:渐变图
顾名思义,非必须。

下面展示几个头发shader例子,篇幅原因不做进一步分析了:


游戏引擎的Shader来渲染(TA)
关于Shader的定位,主要是处理头发混叠、高光形状、动态光影下的表现和一些头发渲染过程的性能优化的。提升表现力上限更多的是靠模型和贴图。
研究了一点文章,尝试从理论层深入分析:
- Kajiya-Kay Model (1989)
相关文章:http://xn--d6q620cxwmmvd/ - Marschner Model (2003)
相关文章:http://www.graphics.stanford.edu/papers/hair/hair-sg03final.pdf - Scheuermann Model (2004)
相关文章:http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Scheuermann_HairSketchSlides.pdf - d'Eon Model (2011)
相关文章:http://www.eugenedeon.com/wp-content/uploads/2014/04/egsrhair.pdf - Double Cylinder Model (2018)
相关文章:https://sites.cs.ucsb.edu/~lingqi/publications/thesis_final.pdf
概述:每个模型基本上都是承上启下的,并且复杂程度逐渐递增,目前游戏实时渲染领域基本还处在Scheuermann Model中,影视行业等离线渲染领域已经逐渐使用DoubleCylinder了。
关于前两个模型,因为已经有高赞知乎介绍过了:https://zhuanlan.zhihu.com/p/27313644 ,这里就简单补充,不重复分析,建议先移步阅读。
展开介绍前,先科普一下以下几个内容:
BSDF和BSSRDF
BSDF(Bidirectional scattering distribution function)是BRDF和BTDF的超集和泛化。所有BxDF功能背后的概念可以描述为一个黑盒,其输入是任意两个角度,一个是入射射线,另一个是反射或透射射线,在表面上的一个给定点。这个黑盒子的输出值定义了给定两个角度的入射光和输出光能量的比率。黑盒子的内容可能是一个数学公式,或多或少地试图模拟和近似实际的表面行为。
可以简单的理解BSDF = BRDF + BTDF;
如下图,在BRDF中,红色虚线的半圆内的光线称之为Diffuse(漫反射),超出红色虚线且与入射光线对称的大箭头是Specular(镜面反射)

次表面散射是光在传播时的一种现象,表现为光在穿过透明物体表面后,与材料之间发生交互作用而导致光被散射开来,光路也在其他的位置穿出物体。光一般会穿透物体的表面,在物体内部在不同的角度被反射若干次,最终穿出物体。

模拟次表面散射的一个方法就是通过BSSRDF(Bidirectional Surface Scattering Reflectance Distribution Function)对材质建模。
下面右图红框处,就是开启次表面散射的效果:

Anisotropic Lighting(各向异性光照)
相关文章:http://www.bluevoid.com/opengl/sig00/advanced00/notes/node159.html
各向异性是指材料的性质会因为方向的不同呈现不同的特性。
一般的光照模型可以简单描述为:
光照模型 = 环境光+漫反射+镜面反射(高光)
在头发光照模型中:
光照模型 = 环境光+漫反射+各项异性高光
镜面反射这里:有别于金属的椭圆高光,头发会形成类似天使环的各项异性高光。如下图:

头发在微观层面是圆柱体,在光线照射在发丝上所形成的高光是基于发丝该点法平面所有法线反射而成的光的积分。

但在游戏中,会使用一个影响最大的法线来进行近似计算,该法线与光线,发丝切线同在一个平面,且NL夹角是锐角。

《原神》的头发却没有做动态的各项异性高光,而是直接将其绘制到头发贴图上。


Microfacet Model(微表面模型)
相关文章:https://en.wikipedia.org/wiki/Specular_highlight#Cook.E2.80.93Torrance_model
1.任何材料表面都是粗糙的,由无数微小的表面组成。
2.这些微小的表面都是光滑的。
所以在Microfacet模型中,着色区域并不能用一个法线向量来表示表面的方向,只能用一个概率分布函数D来计算任意方向的微小表面在着色区域中存在的概率。

笔墨原因,基础概念就介绍到这里,下面开始捋一捋近年来的头发渲染模型:
Kajiya-Kay Model
模型认为头发纤维是不透明的固体圆柱体。

反射被分成漫反射(Diffuse)分量和镜面(Specular)分量:

其中Kd和Ks分别为漫反射系数和镜面系数。请注意Kajiya-Kay模型是方位无关的。本质上是个经验模型。
论文利用了各向异性光照提到的圆柱切面积分,然后在BRDF项上,diffuse和specular分别代入了Lambert模型和Phong模型,进一步简化得到了下面结果:


它只描述了大体上的头发视觉效果,仍然有很多光照成分被忽略了(没有考虑光线在发丝内部传播,没有考虑次表面散射)。
Marschner Model
将头发视为类玻璃的绝缘体圆柱。

考虑了次表面散射并指出头发具有两个不同的镜面高光。

其中Mp代表纵向散射,Np代表方位角散射。
反射光路R:光线到达头发纤维角质层直接被反射。

透射-透射光路TT:光线透射进入皮层,又从中直接透射出去。出射点在入射点的背面。

透射-反射-透射光路TRT:光线透射角质层进入皮层,角质层内层折射,又透射到空气中。可以知道,出射点距离入射点已经产生了偏移。

R是白色的,因为没有通过头发内部的纤维
TRT由于两次通过纤维而着色。

TT路径可以从另一边看到。因为路径通过头发内部的纤维。

根据刚才的光路分析,我们知道,R,TT和TRT任一一种光路实际上可能既包含了纵向散射,又包含了方位角散射,所以可以进一步得出头发上某一点的BSDF:

其中:

Real-Time Marschner 在手机上还是有不小的压力,次年Scheuermann提出了一种实时渲染头发的方案。即Scheuermann Model
Scheuermann Model
该方案是结合了Marschner的结论,在Kajiya的基础之上为实时渲染而设计的,所以也不是能量守恒的。(我们常说的Kajiya+ 其实就是指这个方案
注:因为论文里的公式比较复杂,在游戏里一般使用近似公式计算。Scheuermann和本文后面提出的改进方案就是在这种思想指导下进行的。
Shader输出的最终颜色可用下面的公式来概括:
finalColor = (diffuse + specular1 + specular2) * AO
具体实现如下:
原文请参考:
http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Scheuermann_HairSketchSlides.pdf)

切线朝核心法线或远离核心法线方向偏移:

用偏移的切线来计算高光:

市面上绝大部分手游还是用这个方案来实现的头发渲染。
欢乐麻将采用这套方案渲染的头发如下:

该头发分4个pass渲染,主要是为了提升效率和解决头发渲染层级问题
Pass1.渲染完全不透明的部分:

Pass2.渲染头发背面半透明部分:

Pass3.渲染头发正面半透明部分:

Pass4.ShadowCaster:
这部分主要处理各种光影的接收
d'Eon Model
在Marschner的基础之上,进一步考虑内部的反射和透射现象,可能也是过于相似的缘故,该模型的影响不是很大。所以我们也称该模型为Marschner+。

如下图,Marschner的模型只计算了前三种反射/折射模式,即R、TT和TRT。该方案损失了近15%的能量。dEon模型就将他们考虑上了。核心计算还是逃不开Mp和Np,只是补上了TRRT等情况,这让实时渲染更困难。

Double Cylinder Model
根据解剖学和测量,作者提出了一个双圆柱模型的反射:一个毛皮纤维,其中外部圆筒表示生物的观察皮层,内圆筒代表了散射内部结构被称为髓质。

实时计算不同髓质对光线的影响是困难的,通过观察不同髓质对光线的吸收和反射等表现,录制到数据库中,通过直接查询来提高性能。
模型的定义如下:

截面光路如下:

最终头发颜色由5个分量表示:

更为巧妙的是:通过观察可以得出动物的毛发比人类的头发髓质更大更粗,可以通过调节髓质参数来轻松实现动物毛发效果。

分析完上述模型后,再做个简单的扩展补充:
如何提升光影的表现效果?(注意,这里只是提升光影效果,模型和贴图如果很差劲,是很难靠Shader拯救的)
头发的光影效果一般是以下效果的堆叠:边缘光RimLight、菲涅尔效应Fresnel、各项异性高光AnisotropicSpecularLight、全局光Global illumination。
如果还想进一步提升,可以考虑加入环境光遮蔽Ambient Occlusion、以及上文贴图中提到的Transparency Map和Ramp Map。
后续可以再根据自己项目的要求,定制shader,比如添加间接光补偿indirect lighting:
除了单个毛发/毛皮纤维的外观/反射模型外,毛发和毛皮的光传输还需要模拟间接光照,即不同毛发/毛皮纤维之间的多重光线反射。在实时领域我们常常忽略这些反射效果(太耗),这会导致头发整体偏暗,处理的方式有很多,比如新增控制变量:
从半兰伯特模型中汲取经验,用WrappedDiffuse来代替普通Diffuse的计算方式,来提升头发背光处的亮度,当然,这是能量不守恒的


如何优化Shader,实现Real-Time?
可以考虑优化论文提到的概念和函数,用近似的术语或轻量级的函数代替,举几个例子:
1.上述头发各项异性介绍中,就用most important normal(最重要的法线)来代替法平面上的所有法线。
2.积分在渲染中的使用非常的普遍和重要,比如圆柱的各项异性,抗锯齿,软阴影等。但积分的求解很多情况下并不简单,所以为了简化计算,我们常用蒙特卡罗方法代替直接求解积分。
3.用贴图的Color LUT来避免实时计算一些复杂的光影效果。
4.简化论文函数模型:
将原来的透射模型的参数hTT:


近似改为:



关于引擎
Unity
最新的Unity 2019 LTS版本中,HDRP针对Shader Gragph进行的改良,可以在一个材质球上直接指定为不透明(opaque)或透明(transparent),并且加入了新的Hair Master Node,未来制作毛发相关的Shader将会更得心应手。
https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@7.1/manual/Master-Node-Hair.html

对于麻将的效果,相同贴图和模型我用HDRP实现了一下:(手机游戏建议使用URP,用HDRP纯粹是为了看极限效果)

加了AO,层次感更加明显了,但是依然没法入眼,还是那句话模型和贴图是决定头发表现上限的东西,Shader只是锦上添花。
UE4
NVIDIA提供了名为HairWorks的毛发解决方案。HairWorks包含DCC工具集成和毛发实时渲染与模拟。自4.16版起,UE4中的HairWorks就被弃用了。
虚幻引擎4.24版本中推出基于发丝的毛发渲染系统Groom,最好是在4.25以后使用。并且这块功能官方目前仍标记为是测试功能,暂时不建议用到正式产品上。
官方文档有比较详细的教程:https://docs.unrealengine.com/zh-CN/Engine/HairRendering/index.html
总结
头发模型的制作主要分为基于面片和基于引导线,基于面片需要靠设计师直接操作点线面,比较适合制作不太复杂的头发模型;基于引导线需要美术师掌握XGen等相关工具链,熟练操作后,效率甚至比基于面片高,适合用来做偏写实风格的角色头发。模型直接影响头发的体积感和层次感,以及一些发丝细节。后期制作头发布料效果也需要依赖的模型制作。
头发贴图的类型多种多样,高质量的Albedo和Normal Map可以很大程度上提升头发的品质,AO Map和Transparency Map在制作3A或PC游戏时也经常使用。绝大部分游戏的头发渲染 一般是通过高模来烘培出Normal map,Specular map,AO等贴图,再通过图片查找表的形式去索引所需要的颜色法线等信息应用在中低模中。既能节省顶点数,又能表现出逼近高模的渲染效果。
头发渲染:主要从论文原理出发,从kajiya的各种trick到double cylinder的基于真实头发模型的物理渲染,解释头发的各种现象。在此基础上做出的Shader才能更加逼近现实中的效果。同时也补充介绍了头发shader的基础实现和优化。
最后,补充了一下关于Unity和UE4提出的头发渲染解决方案,供感兴趣的同学升入挖掘尝试。
REFERENCE
https:// github.com/AdamFrisby/U nityHairShader https:// docs.unrealengine.com/z h-CN/Engine/HairRendering/index.html
【GDC2004-Hair Rendering and Shading】 http:// web.engr.oregonstate.edu /~mjb/cs519/Projects/Papers/HairRendering.pdf
【SIGGRAGH2004】 http:// amd-dev.wpengine.netdna-cdn.com /wordpress/media/2012/10/Scheuermann_HairSketchSlides.pdf
【知乎】 https:// zhuanlan.zhihu.com/p/27 313644 https:// zhuanlan.zhihu.com/p/53 407479
【PBR】 https:// blog.selfshadow.com/pub lications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf
【BRDF】 https://www. cnblogs.com/herenzhimin g/articles/5789043.html
【次表面散射】 https:// zhuanlan.zhihu.com/p/21 247702?refer=graphics https://www. cnblogs.com/jaffhan/p/7 382106.html 论文:
【Kajiya】 https://www. cs.drexel.edu/~david/Cl asses/CS586/Papers/p271-kajiya.pdf
【Marschner】 http://www. graphics.stanford.edu/p apers/hair/hair-sg03final.pdf
【Zinke】 http:// citeseerx.ist.psu.edu/v iewdoc/download;jsessionid=CD92117DF7B74A608679B5D227096472?doi=10.1.1.94.1025&rep=rep1&type=pdf
【d'Eon】 http://www. eugenedeon.com/wp-conte nt/uploads/2014/04/egsrhair.pdf
【Lingqi】 https:// sites.cs.ucsb.edu/~ling qi/publications/thesis_final.pdf