细致到毛孔 ! 深度揭秘超真实皮肤的实时渲染技术(下篇)

发表于2017-09-20
评论23 1w浏览

| 导语 腾讯互娱NEXT研发中心有幸参与了MEETMIKE项目,几位实时渲染和图形学的研发人员帮助提升了数字人脸部皮肤的细节和真实性,与Epic Games合作开发完成了一套全新的复杂的皮肤着色器(Skin Shaders)。 在此,我们将分两部分为大家揭秘超真实皮肤渲染的相关技术。上篇为皮肤渲染的相关理论以及为了验证而做的LookDev,下篇为技术层面的详细介绍以及跟Epic大牛身上学到的技能点。

 

改进深度揭秘

1.       2nd Specular Lobe

皮肤的高光对于展现皮肤细节有很重要的作用,在《Next Gen Character Rendering》中采用Base Tile DetailingNormalRoughness,可以达到很好的细节,这次MikeNormal也是用类似的方法。但这里的第二层Specular Lobe指的不是Tile Detail,而是根据第一层的Roughness Scale一下,又算了一层Specular,将两层Specular混合一下,混合系数为第一层占85%,第二层占15%。具体比较图1718

17 一层Specular Lobe

18 两层Specular Lobe

这个算法其实非常简单,Jorgeppt中也给出了实现的细节(19),实现到UE4中也很容易。

19具体实现

但是用到测试数据上发现根据Jorge给的参数调不出来很好的效果,在nVidiaFaceWork中正好有这个功能,代码和我们实现的非常接近,不同的是他们采用的BeckmannSpecular模型,而UE4采用的是GGX,但是这两个模型应该不会对第二层Specular Lobe有影响。因此怀疑数据的设置可能有不同,将FaceWork的数据导入到UE4中发现效果非常明[6](20)。原因是因为测试数据的Roughness值调的太高了,这样第二层和第一层的Specular算出来差别不大,混合之后几乎看不出来差别,因此Roughness需要整体的调整的低一些,效果就会很明显。

20 FaceWork 两层Lobe比较

其实这个技术的目的是想通过第二层Specular Lobe来表达高光更聚集的光滑区域(21),第一层Specular Lobe表达高光比较分散的粗糙区域(22),最后混合之后会出现更多细节(23)

21 第二层 Specular Lobe

22第一层 Specular Lobe

23 两层Specular Lobe混合

这个技术虽然简单但是很大程度提高了皮肤的细节,属于性价比非常高的技术,大部分人都是从Jorgeppt第一次了解到这个技术,而实际上这个技术早在2007GDC有一篇nVidia的文章名字叫做“Advanced Skin Rendering[4]中就出现过。更夸张的是当时采用的是4Specular Lobe而不是2层。见图24。我们也实现了这个方法,而且跟2Lobe的计算指令差不多,但是参数是在太多太难控制,所以最终还是决定只用2层。

 

24 四层Specular Lobe

Specular Model

UE4Specular模型都是采用的GGX,皮肤也不例外,这次调节皮肤的Level ArtistEpicPeter,PeterPixar工作了15年,一直负责调节人物的材质,对于皮肤的表现非常有心得,根据Peter的经验,Pixar之前用的Specular模型都是Beckmann,后来都切换到GGX,大家对于金属类的表现都非常满意,但是皮肤感觉塑料感强了一些,因此对于皮肤是个例外仍然采用Beckmann。两个图像略微有点差别,Beckmann计算出来的Specular比较亮的区域稍微弱一些,一般人很难觉察出来,但对于专业人员还是能看出其中的区别。

25 GGX

26 Beckmann

 

2.       Back Scattering

Back Scattering是指光线照射到比较薄的透明物体上,有一部分光会产生透射,而RGB扩散的范围不一样,红色的扩散的更远一些,所以耳朵和鼻子的部位会有红彤彤的感觉。而我们就是要模拟这一现象。

方法1

因为只有比较薄的地方会有这种现象,所以需要一个可以描述厚度的信息,EA2011GDC展示了他们采用Local Thickness来实现透明物体的次表面散射,虽然不是物理和数学正确的方式,但是效果还是可以接受的[7]。图27

https://colinbarrebrisebois.com/category/subsurface-scattering/

27 EA采用的材表面散射材质

但是因为其没有灯光方向对应的厚度,也就是没有光线在物体内部传播的距离,其衰减是依靠于对光线方向按照Normal扰动得到的,这样没考虑到会有别的物体投射阴影;每个材质有个参数Power可以调节光照衰减,但是这个也是依赖于Normal对光照方向扰动的结果,这样导致对于厚度不一样的地方算出来的衰减是一样的。

我们一开始尝试了一个在这个基础上改进的算法,仍然按照Forsbite的方法计算一个Local Thickness,图28是对应的LocalThickness贴图,Local Thickness会被保存到GBufferCustomData贴图中,在计算光照时使用。

28 Local Thickness

29 Local Thickness映射到模型上

UE4针对采用Subsurface类型的材质的物体计算了一个SS Shadow (Subsurface Shadow),这个SS Shadow SampleShadowDepth和一般的阴影是一样的,一般阴影计算只需要考虑是否处于阴影中,而SS Shadow是对每次Sample算一个真正意义的Thickness,然后按照这个Thickness算一个指数变化,这样就可以产生将变的阴影,对于比较薄的区域,比如鼻子,耳朵即使是在背光方向其SS Shaodw也不是完全黑色,这样就很有透射的感觉了。如图30,但是这样除了耳朵和鼻子外,所有阴影交接的区域都有这样的感觉。Local Thickness乘以SS Shadow就可以保证只有比较薄的区域才会有透射的感觉。当灯光转到左边耳朵对应的方向时,因为SS Shadow将变的区域是可以调节的,可以保证右边耳朵的SS Shaow完全是黑的,也就是说不会产生漏光(31)

30 SS Shadow

31

可以考虑为LocalThickness加入一些细节信息,比如可以画一些血(32),这样产生的透射可以清晰的看到血管(33)

32 Local Thickness加入血管信息

33 能看到血管的透射

这个方法的优点在于:

1.    非常容易实现,SS Shadow的计算已经有了可以直接用

2.    非常稳定,对于UE4所有光源类型都可以工作,即使对于Directional Light也可以有非常稳定的结果

3.    Local Thickness可以加入很多细节信息

缺点也很明显:

1.    缺乏体积感

2.    SS Shaow的计算因为需要读取ShadowMap的值,所以无法使用tex2DProj,因此开销也是比较高的

3.    需要Local Thickness贴图以及占用CustomData的一个通道

 

方法2

Jorge在《Next Gen Character Rendering》中花了很大的篇幅来介绍透射相关的技术[8][9],最早采用单次Sample,ShadowMap精度很高时可以达到很好的效果图34,当ShadowMap精度降低时,就会非常明显的黑色锯齿图35,所以需要和ShadowFilter一样需要多次SampleSample 16次可以达到很不错的效果,但是16Sample开销太高,所以Jorge采用了Random Roatete 2 Poisson Disc Sample,虽然这样算出来的结果噪声很明显,但是经过SSS Blur Pass之后会非常平滑(36)

34 单次Sample透射

35 Shadow精度不够有明显瑕疵

36 多次Sample产生的透射

Jorge的方法在Demo中工作的非常好,因为ShadowMap的精度可以保证,但是真正集成到引擎中就会发现ShadowMap精度往往没那么高,因此很多情况下效果会很差。我们的方法和Jorge的类似,但是有些方法做了一些改进:

1.    Thickness计算更准确

2.    去掉Random Rotate带来的噪声

3.    加入Phase Function

4.    加入Refrac

5.    Profile信息Cook到每个Profile Kernel的尾部,根据Thickness Sample

Thickness计算

JorgePaperThikckness的计算是沿着像素的-Normal往物体内部延伸了一段,然后将这个位置投影到ShadowMap空间这样可以得到其在ShadowMap空间的Depth,同时也可以得到其在ShadowMap空间的投影位置,这样前面计算的DepthSample Shadow Depthd的值相减就可以得到Thicknes(37),但是这样算出来的Thickness是比实际的要短的,应该加上NormalScale的一部分,我们这里做了一些修正,会比原先的效果好一些;另外在很薄的区域NormalScale延伸的距离可能会跑到Mesh外面,这时候Jorge认为Thickness是很大的也就是前面ShadowMap精度比较差的时候有很明显的黑色锯齿,我们这里处理的情况是一旦出现这种情况就Clamp到一个很小的Thickness,这样就消除了ShadowMap精度很差带来的黑色锯齿问题。

Thickness是在ShadowProjection的时候计算出来的,保存到ShadowBufferAlpha通道中,Alpha通道之前是被SS Shadow占用,也就是说为了支持透射,对于Subsurface Profile类型的材质SS Shadow就无法支持了,SS Shadow之前用到的地方也很少,所以影响不是很大。因为阴影Pipeline的原因最后保存到Alpha通道的其实是1-Thickness,后面会讲到为什么。

37 Thickness计算

Random Rotate的概念虽然听起来很有道理,但在实际尝试中发现有些像素的2Poisson Sample会和周围邻域的Sample距离很近,这样让Sample变的不均匀,而Random RotateUV是从屏幕空间来的,所以依然会带来按屏幕uv分布的噪声。我们是直接去掉Random Rotate,只做了2Poisson Sample,经过SSS Blur之后结果非常平滑,体积感也很好(38)

38

 

Phase Function

光线在皮肤内散射,最后在薄的区域产生透射,透射的强度和观察的角度有关系,越是沿着逆光的方向应该越(39)Phase Function就是用来描述这样的分布,我们采用的是HG Phase Function

39 加入Phase Function

 

Refraction

皮肤属于半透明物体,光线在其内部散射,最后透射出来时会产生折射,可以想象一下光线经过玻璃透射产生折射的情形,只是皮肤的折射相对来说弱很多。引入折射后会带来一些微妙的变化,让透射产生更多变化。

40 折射开启

41 折射关闭

Profile

有了前面算出来的Thickness就可以计算出透射,因为透射只和光线穿过的路径也就是这里计算出来的Thickness有关。这个透射的ProfileSS BlurProfile到底是不是一个一开始一直是有疑问的,后来发现在Jorgedemo中是图7shader来计算透射的,可以看出输入参数只有Thickness,这里的ProfileSS Blur用的是同一个,这也就回答了透射和SS BlurProfile是同一个的问题;6个指数还是开销很高的,所以最后只采用了最后的exp,这样算出来的透射其实就只有一个红色的色调,而从真实照片中观察可以看出最薄的区域其实有略带黄色,用他的做法就无法做到,他也建议把Profile Cook到贴图中,直接SampleSample一个贴图要比算6epx快很多,这个在他的ppt中也提到过。我们这次采用了将Profile信息Cook到每个Profile Kernel的尾部(42),根据Thickness Sample,就可以做出来耳朵最薄的区域有点发黄,慢慢渐变到红色。

42透射Profile

SpotLightUE4中最容易实现高质量透射的光源类型,主要是因为其阴影计算简单采单,一个SpotLight对应一个ShadowmapDirectional Light采用CSM情况比较复杂,Point Light采用Cubemap Depth情况也比较复杂。图43SpotLight渲染出来的透射。

43 Spot Light透射效果

透射计算是否正确是需要经过验证的,这个验证不像我们之前做游戏那样美术目测觉得差不多就过关了,UE4是一个商业引擎,必须经过严格的验证才可以说明这个功能是正确的。这里的验证就是用前面提到的LightStage拍摄的参考照片和UE4模拟LightStage渲染出来的图片比较,这是一件非常严格的事情,真实照片和渲染出来的照片几乎可以达到高度吻合,很多地方像素都匹配的很准确,这将事情的难度非常高,要求拍摄时演员纹丝不动;生成的模型和演员极高度匹配,虚拟的相机完全还原真实相机,灯光方向参数完全一致。图44给出了四个不同光照方向模拟透射和真实照片的比较,可以看出还原度非常高。图45是采用Wipe模式,拖动条左右移动可以查出真实照片片的一部分,从而和渲染出来的图片逐像素比较。说实话第一次见这样的场面,感觉跟做电影一样严格。

 

44 不同角度比较透射的效果

45 Wipe模式精确比较效果

Point Light略微复杂一点,因为采用Cubemap Shadow Depth,需要得到当前处理像素对应的Cubemap ID以及SideUp向量,然后按照SideUp构成的平面做Poission Disk SamplePoint Light采用的是Perspective Depth,因此当耳朵处于点光源半径附近时Depth带来的误差会比较大,会略微有点闪的感觉,但是好在这时候光的亮度已经衰减的很微弱了,不是很明显(46)

46 Point Light透射效果

Directional Light采用CSM,虽然第一级的精度还不错,但是对于计算透射来说还是精度太差,人物头部在ShadowMap占的像素数目少得可怜,所以无法得到好的结果。CSMcascade可以调节,如果将前面两级的精度增大会很有效的提升透射的质量,但是这样会对ShadowDepth带来不少额外开销。经过一番讨论得知,Directional Light可以对某些物体开PerObject Shadow(47)PerOjbect Shadow相当于为了提高一些物体的阴影精度单独开了一张ShadowMap,按照Shadow Projector的方式投射该物体的阴影,精度比其他物体要高很多。PerObject Shadow需要和其他Shadow最后Merge到一起,这通过ShadowProjection时采用Min操作来保证,这也是为什么前面算出来的Thickness需要用1-Thickness,也是为了取Min。通过PerObject Shadow渲染出来的透射效果非常好,理论上应该和SpotLight的质量是一样的(48)

47 PerObejct阴影设置

48 Directional Light透射效果

从上面可以看出,实现一个Demo相对来说比较容易,但是整合到引擎中问题还是很多的,需要考虑各种光源类型,还需要和Pipeline相结合,还需要做各种严格的比较验证。

3.       SS Profile Model

Disney Approximate Reflectance Profiles用于计算次表面散射[10]。和UE4原有的高斯模型相比,Disney模型数学形式上更加简单,而且模型的参数更加具有物理意义。尽管这个模型是经验模型,但是它十分接近通过蒙托卡罗采样方法得到参考结果。模型是由两个指数加和的形式表现出来,输入参数是衰减度(albedo)和平均自由路径长度(mean free path length)。这两个参数的物理属性是由每一种次表面材质决定的,比如皮肤,玉,蜡烛,牛奶等等。这个模型可以替代基于物理模型的主要原因如下:

1. 两个参数用户友好,有物理意义;

2. 多散射模型包含了部分单散射的效果;

3. 更快速的估计,实现简单不需要查表;

4. 没有修正系数因子;

5. 重要性采样操作更加简单。

 

用于蒙托卡罗积分的数学表达式如下图:

Rr):Approximate Reflectance Profile

distance

l : mean free path length

A : albedo

s : scaling factor

sA(albedo)的函数,形式如下:这个表达式和蒙托卡罗参考结果相比只有2.6%误差。

UE4实现

UE4是基于屏幕空间的次表面散射实现架构。我们保留原有的高斯profile模型的基础上开发了新的Disney profile。用户可以选择使用哪一种profile。两种模型有着不同的参数。次表面散射profileUI如图49

49 Profile UI

参数”Falloff Color 用于切换两种模型,不勾选代表使用Disney模型,这样AMean Free Path就用于控制材质,这两个参数可以参考Pixar对不用次表面材质的测量数据,这样UE4的参数就和Pixar的离线渲染的参数对应。

50 不同材质参数

数据和结果对比

两种profile的曲线对比:

51结果对比:Disney(左图) VS Gaussian(右图)

52结果对比:Disney(左图) VS Gaussian(右图)

很遗憾这次没来得及验证,所以最后在Mike Demo中并没有采用这个先进的算法, 后续工作将会采用这个方法。

 

4.    Texture Resolution

UE4目前渲染可支持的最大贴图分辨率是8k*8k,对于一般游戏来说这个分辨率应该足够了,但是对于需要表现无尽细节的Digital Human还是略微不足,这次MikeDemo是有计划使用16K扫描的贴图,DX11现在最大支持的贴图也限制在16k,这样的精度是目前能做到的最高精度,我们也做了相应的开发可以让UE4支持16k贴图,但是可惜的是最后数据出了些问题,没用用到Digital Mike上。


5.Epic身上学到什么

1.    r.CompileShaders CMD

UE可以用Ctr Shift 。动态编译Shader,随便改一行,编译一次shader需要10分钟左右,这对于Shader开发非常痛苦,浪费了很多时间,经常一天大概有2个小时浪费在编译shader上。后来去了Epic一起开发的时候,改了一行ShaderLevel Artist Peter看效果,我说你等几分钟再过来吧,变编译一次Shader需要几分钟,他说不用编译所有的用命令行r.RecompileRenderer DeferredLightPixelShaders可以之编译你需要编译的Shader,试了一下果然几秒就结束了,而之前的状况是所有Shader都要编译,而现在只需要几秒,就算改的是共同的Include文件也很快,这样一下就节省了很多时间。

 

2.    RenderDoc

       UE4虽然有自己的GPU Profile,但是那个东西一点都不准,所以要正确的分析GPU开销,是不能用这个功能的。我们之前分析GPU性能时使用的的工具是IntelGPA,在分析性能开销数据时还是可以起到很大作用,但每次打开CpatureFrame数据时需要较长时间,而且操作也不是很方便;很多时候还需要对渲染的东西Debug,比方看深度,Debug Shader之类的操作,GPA以前可以Debug Shader,新的版本已经没有这个功能了。PIX也可以DebugShader,之前用来查了很多很难查的Bug,虽然Debug的是汇编Shader,但是相对来说还是比较容易的,因为Shader的汇编相对来说比较简单,但是PIX现在对于很多游戏和应用都无法Attach,或者很容易CrashUE4现在就无法用PIX来分析。而这次遇到一个很难查的问题的确需要DebugShaderEpicLevel Artist WuMinJie推荐了RenderDoc[12],原因是Epic的渲染程序员都在用这个,可以试一下能不能DebugRenderDocCrysis的一个程序员开发的,对于目前主流的图形API都支持,功能非常强大,非常容易使用,而且最重要的是拥有DebugShader的功能图54RenderDoc也有Profile GPU开销的功能,但是每次使用得到的数据会有不少的误差,这一点相比而言还是GPA更准确一些。

53 Time Profile

54 Debug Pixel

 

3.    Screenshot with RV to compare result

前面已经提到UE是一个商业引擎,整合一个新功能进去必须要通过严格的验证,而不像我们之前开发游戏美术同学觉得效果差不多就可以了。为最终效果拍板的是Epic CTO KimKim在电影行业工作了很多年,曾经获得过奥斯卡奖项,《黑客帝国》就是Kim参与制作的的电影之一,Kim加入EpicUE4明显向电影行业靠拢,用UE4渲染电影现在很流行。Kim要求非常高,在开发Mike SIGGRAPH Demo时就很有远见的在LightStage中拍摄了参考照片,这些参考照片用来验证开发的效果是否正确。Level Artist在关卡中建立蓝图来模拟LightStage,通过350张图片来验证是否可以达到照片级别,350张图片涵盖了光照从各个角度照射过来的可能,每次比较的时候是在Epic一个小会议室里,关掉所有灯光,用最好的屏幕投出来开最终的效果。

 

4.    Further understood the rendering pipeline

和我们对接的渲染程序员是EpicBrian KarisBrianUE4开发了很多高级功能,Physically Based ShadingTAASSRDigital Human相关特性皮肤,眼睛和头发,他是SIGGRAPHPhysically Based Shading小圈子的成员,曾经多次在Physically Based Shading作报告。他这次给了我们很多指导,虽然我做了很多年渲染,但是UE4Pipeline因为要兼容的东西太多,还是很多地方不清楚,Brian都一一耐心给了解答,并且讲了很多以前不了解的内容。在一起看性能优化的时候给了很多中肯定建议,有很多以前不知道的命令行可以开启一些特殊优化,对整个Pipeline有了更深入的理解。

 

5.    Level artist 能力非常强

Peter是这次的主要Level Artis,负责了皮肤,头发,眼睛材质,灯光和LightStage的开发,他以前在Pixar参与电影的制作,已经工作了15年,参与了8部电影的制作,专职负责角色的各种效果,对于如何调节人物有非常独特的方法。我给Peter看早期透射的效果,看之前去掉了乘上BaseColor的代码,Peter看了后说,效果还可以,你能试一下乘上BaseColor吗?这令我非常惊讶,眼睛也太毒了吧,这都能一下看出来JUE4Specular模型都是GGX,但是Peter坚持要试一下Beckmann,原因是Pixar之前都采用的Beckmann,后来全都换成GGX,大家都觉得很不错,尤其是金属表现的非常好,但是有一个例外就是皮肤感觉塑料感强了一些,所以最后皮肤还是采用Beckmann。我们表示要帮Peter试一下Backmann看看效果,他说你们任务挺紧的,我怕耽搁你们的时间,我自己试一下,第二天我发现他已经把Shader改好上传了,对于国内的Level Artist来说这是一件很难的事情。

 

6.  后续工作

目前的皮肤虽然已经做的非常不错了,但是还有提升空间,SS Blur之后在比较暗的地方会有比较明显的BandingDisney Profile需要经过严格验证,16K贴图可以极大的增加细节,加入这些可以让静态的Mike变得非常真实,但是一旦有了面部表情动画皮肤会拉伸,产生折皱,这样现在的动画方案效果就跟不上了,2015SIGGRAPH有一篇文章介绍的是皮肤动起来之后产生折皱的问题,这也是后面皮肤需要研究的新方向[13]

 

 

参考文献

[6].   Faceworks https://github.com/NVIDIAGameWorks/FaceWorks

[7].   Colin Barre-Brisebois,Marc Bouchard. 2011. Presentation at Game Developer Conference 2011. Available onlinehttps://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/

[8].   Jorge Jimenez, David Whelan, etc. Real-Time Realistic Skin Translucency

[9].   Jorge Jimenez. Next Gen Character Rendering GDC 2013.

[10].         Per H. Christensen, Brent Burley. "Approximate Reflectance Profiles for Efficient Subsurface Scattering" Presentation at SIGGRAPH 2015. Available onlinehttps://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf

[11].         Per H. Christensen, Brent Burley. "Approximate Reflectance Profiles for Efficient Subsurface Scattering" Presentation at SIGGRAPH 2015. Available onlinehttps://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf

[12].         RenderDoc. https://github.com/baldurk/renderdoc

[13].         Koki NaganoGraham FyffeOleg Alexander etc."Skin Microstructure Deformation with Displacement Map Convolution"http://gl.ict.usc.edu/Research/SkinStretch/

 

细致到毛孔 ! 深度揭秘超真实皮肤的实时渲染技术(上篇)

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

标签: