图形引擎实战:皮肤效果
大家好,我是来自搜狐畅游引擎部的puppet_master,很高兴有机会来继续分享角色渲染的皮肤渲染的部分。我们的皮肤方案也还在不断迭代当中,疏漏之处难免,也欢迎大家批评指正。
皮肤渲染在整个角色渲染的部分中属于最重点的一个部分,如果说除了PBR以外,只能给角色单独制作一个效果,那一定就是皮肤了。和头发一样,皮肤也是渲染领域的难点之一,一方面是超写实类的皮肤,由于皮肤的结构复杂导致的细节以及光影表现的复杂;而另一个方面难点则在于,不同类型美术风格的项目对于皮肤要求是不同的,如何用一套方案适用于从超写实到风格化的不同项目而不必要每个项目都进行单独定制也是我们需要考虑的一个问题。
皮肤的特性
正式开始之前,我们需要先梳理一下皮肤的特性。
红润:“手如柔荑,肤如凝脂”在古代我们要想表达小姐姐的皮肤只能通过这样的诗句,而在现在我们要在虚拟的世界里面还原皮肤的效果也是需要重点来表现皮肤的特性就是红润,这是所有皮肤都需要的特性,也是区别于其他材质最重要的特性,让我们的皮肤显得有生气。
细节:而如果是特别写实类型的皮肤,则需要更多的细节的表现,如毛孔细节。虽然小姐姐类型的角色我们一般是不希望太明显的毛孔的,但是如果你想制作一个可以近距离特写的真实的糙汉子,那细节则是少不了的。
油脂:皮肤分为真皮,油脂层等多层的结构,表面的油膜也会导致皮肤的高光表现不同寻常
投射:皮肤薄的位置如耳朵和鼻头等地方的在背光的情况下会有透光的表现。
皮肤有红润,细节,油脂,透射的几个特性。但是细节,油脂本身可以用常规的渲染方式实现,并且对于非超写实的角色而言,影响效果不大。而透射对于背光等条件下的表现才更明显。只有红润的特性是皮肤中最为明显的一个性质,也是皮肤效果表现的重点。
次表面散射原理
皮肤的红润的特性来源于一个现象,次表面散射(Subsurface Scattering),简称SSS或者3S。
常规的光照模型我们可以用BRDF来解释,如下图侧黄色光线,光线在物体表面反射,或者进入表面后很近的部分(可以理解为一像素)内的距离内进行散射我们都可以将其归结为BRDF,但是皮肤等材质光线很多情况下会更多的进入材质内部进行散射甚至多次散射然后从距离入射点更远的位置透射出来,如下图中蓝色绿色的光线,出射方向和位置都偏离了常规的反射逻辑,这就无法使用常规的表面散射模型进行解释了,因为光线在内部散射后光子的运行轨迹十分复杂,极少数是单次的散射,更多的则是多次散射,即使在离线渲染也很难进行真实的计算模拟。因此我们更多的是使用各种近似的方案来模拟这一现象。
实际上,所有的材质都有次表面散射的现象,只是绝大部分的材质这个分布都集中在入射点附近,而当绝大部分分布都集中在入射点时,我们的次表面散射就回归了我们常规的BRDF表面散射,也就是上图中右边黄色光线的表示的情况。因为光线的散射很复杂,所以我们也可以直接摆烂,不考虑散射出来的方向对最终结果的影响,那么实际影响额外出射结果的因素的就变成了距离,也就是说我们可以把一个像素上的散射密度分布与其散射的距离有关,我们可以将这个密度分布函数称之为Diffusion Profile,用来描述在入射点周围散射光线分布的密度。我们假设使用白光照射均匀的平坦的表面,会在入射点周围进行散射,对于出射点部分的散射结果的第一取决因素就变成了距离入射点的距离r。
对于不同颜色的光,材质对其的散射程度也略有不同,对于皮肤材质则是红光>>绿光>蓝光,红光远比蓝绿两色光散射的范围更大,因此这也是为什么我们感觉皮肤会有白里透红的感觉。如下图,正如一个纯白光照到我们的皮肤上,散射的结果应该及时一个中心点周围的光晕表现。
屏幕空间次表面散射
我们没有办法模拟所有的光线,因此可以通过几种方式来实现,比如最暴力的纯蒙特卡洛的方案,也可以通过Dipole偶极子或Multipole多级子来描述这一变化分布,但是随着相关技术的不断的发展,开始流行了一个流派就是通过多重高斯函数来拟合这一变化曲线,我们看上图的曲线,实际上部分的曲线的变化有点类似我们概率里面学习的高斯分布(正态分布),但是一条曲线并不能完美的拟合皮肤的分布,因此我们需要通过多个分布加权得到最终的结果,此外,RGB需要给出不同的权重来体现散射程度的不同,下图为一个比较普遍的皮肤RGB高斯和分布表格:
高斯和分布的次表面散射的优势在于易于扩展,我们可以根据不同的高斯分布来组合形成对应的曲线效果,但是坏处就是我们需要实现N个高斯分布的计算,这就导致了很大的性能开销。因此就有了一些额外的方向的优化,Separable Subsurface Scattering,把二维卷积用两个一维卷积近似,虽然有些计算数学上是不正确的,但是结果上是近似的,但是性能上得到了很大的提升。
但是上面的方案,有一个最大的问题在于Artist Friendly的问题,笔者曾经也集成过一版Separable Subsurface Scattering效果,两重高斯核,这个内容对美术同学而言比较难以理解,所以导致的最终结果就是盲调,但是如果只是少量的参数还可以,但是双重两个Scattering Distance * 3个颜色通道,6个参数基本上就会被玩坏,加之采样数少之后,闪烁比较明显,可能会依赖AA,所以并没有取得太好的效果。
梳理近年来关于皮肤渲染的新的方向,可以发现一个新的名字Burley's Normalized Diffusion Profiles,其实还是Disney PBR中的其中一项。换句话说,实际还是通过曲线来拟合最暴力的蒙特卡洛的方法,只是不是那么死板,非得使用多个高斯分布来拟合,而是直接用一个合适的曲线来拟合,但是保证整个分布是Normalize的,然后通过重要性采样来实现。按照迪士尼官方的说法,这个曲线比早期的偶极子等模式更加贴合蒙特卡洛的暴力算法。
Disney的模型向来非常照顾美术同学的感受,从PBR我们就能非常感受到他们为了精简参数所做的努力,以至于把这个变成了业界标准。而Disney的Diffusion Profiles一样秉承了这一理念(PBR同时期的产物,但是Disney SSS近年来才在实时渲染领域流行起来),所以Disney SSS的另一个最大的优势就在于参数精简。实际我们的Scattering的影响参数只有两个,第一是材质颜色的Albedo,这个理论上不算是额外的输入参数了,另一个就是不同颜色的光散射的强度的距离,这个也可以用一个RGB来表示,因此,我们实际对次表面散射的输入就只有这一个值。
了解完了基本的原理,我们再来讨论一下次表面散射的实现。因为实时渲染的性能考虑,我们可以跨过Texture Space的实现来直接来到Screen Space的实现。我们根据输入的RGB不同的散射值生成一套完整的Normalized权重分布系数,换句话说也就是卷积核,后续的过程实际就类似于高斯模糊,我们用卷积核来对屏幕空间的结果进行加权求和,就能得到次表面散射的结果。而高斯核的生成,我们可以使用预计算的方式根据参数生成一套合适采样点,当然也可以使用逆采样变化来动态生成采样点。
如果对Specular进行卷积操作会导致高频的高光表现失真,以此我们首先需要把皮肤的渲染结果拆分Diffuse + Specualr分别存储,而比较好的方案就是MRT,直接将渲染结果拆分即可,这样我们只针对Diffuse部分进行卷积操作,然后叠加Specualr即可。
Unity的HDRP使用的就是Disney SSS,我们在URP上也还原了这一效果。对于详细代码感兴趣的同学可以直接down一个HDRP的版本来学习哈,关于具体实现就不过多费周章啦。下面我们来分析一下次表面散射的效果。
我们来看一下皮肤的最重点的一个特性,就是润,如果没有这一个特性,皮肤的感觉就会像如下图所示的表现,粗糙没有生气:
而通过卷积操作,让粗糙的皮肤经过了磨皮的效果,显得更加圆润,而有生气。在这里,我们对RGB三通道进行了均匀的散射值,得到的就是一个整体仅有润的体现的皮肤的质感。
那么,我们进一步的拉开RGB三色的散射值,让红色的散射范围最强,绿色和蓝色略微有一些散射,这样就能模拟出真实的皮肤的明暗交界处的白里透红的感觉,当然,红的程度是和皮肤性质和个人喜好有关:
屏幕空间次表面散射的方案,我们可以直接实现皮肤的红润的特性,效果较好。但是相应的卷积以及拆分Diffuse和Speular等操作的开销注定让这个方案不可能是一个性价比很高的方案。因而实际屏幕空间的效果仅仅是对很近的近距离特写下的皮肤的质感有着很大的提升,但是当皮肤的占屏比没有那么高时,润的特性相应就体现的不是那么明显了。那么,在非特写的情况下我们更多的能注意到的特性就是红(红并非指全红色,而是皮肤的光照过渡非黑白,而是加入了一些偏红向的颜色过渡),那么有没有什么更经济适用的方案来实现红的特性呢?
预积分次表面散射
次表面散射技术也经历了很多的发展历程。实际最早的方法就是Wrap Lighting的方案。比如半兰伯特光照,到卡通的ramp光照,我们可以根据自定义的ramp图或者权重来调控光影的变化结果,让明暗过渡不走寻常路,就可以实现不同于常规材质的更柔和的暗部变化。相比于卷积的次表面方案的原理的角度来实现,wrap lighting的方案更多的是从表现结果反推效果实现,甚至早期我们可以直接通过自发光+mask的方案直接叠加一个颜色到皮肤上,也可以实现一个次表面散射的效果。
直到Pre-Integrated Skin Shading这一个概念的出现,方案根据次表面散射的原理将真正光影变化的卷积结果bake到了贴图中,虽然中间经过了很多的近似的计算,但是让贴图ramp的方案上升到了有理论依据的ramp贴图,而不是随意绘制的ramp。这个方案一方面以一个十分廉价的开销实现了不错的皮肤红的过渡表现,另一方面打通了卷积次表面的理论到结果派和ramp次表面的结果到理论派的鸿沟。
我们来看一下标准预积分次表面的效果的原理。我们根据观察的结果会发现一个规律,次表面散射最容易发生的位置实际上是两个地方:一是光影的明暗交界过渡带,二是部分比较凹凸不平的地方,比如鼻子,眼窝等地方,换句话说也就是曲率变化比较明显的地方。明暗的过渡我们可以通过NdotL来表示,而曲率我们也可以通过length(fwidth(worldNormal)) / length(fwidth(worldPos))得到,因而这样我们就有了两个0-1区间的变换因子,我们把结果烘焙到一张贴图上,实际计算时就可以将复杂的计算直接用贴图采样的结果来表示了。烘焙贴图的代码如下。
[ContextMenu("BakePreIntegrateSSSTexture")]
public void BakePreIntegrateSSSTexture()
{
var tex = new Texture2D(textureWide, textureHeight, textureFormat, false);
for (int i = 0; i < textureWide; i++)
{
for (int j = 0; j < textureHeight; j++)
{
var x = Mathf.Lerp(-1.0f, 1.0f, (float)i / textureWide);
var y = 2.0f * 1.0f / ((float)(j + 1)/ textureHeight);
//ndotl采样x轴,区间(-1,1)重新映射
//1/r采样y轴
var val = IntegrateDiffuseScatteringOnRing(x, y);
tex.SetPixel(i, j, new Color(val.x, val.y, val.z));
}
}
tex.Apply();
texture = tex;
}
public Vector3 IntegrateDiffuseScatteringOnRing(float cosTheta, float skinRadius)
{
float theta = Mathf.Acos(cosTheta);
Vector3 totalWeights = Vector3.zero;
Vector3 totalLight = Vector3.zero;
float a = -Mathf.PI / 2.0f;
const float inc = 0.05f;
while(a <= Mathf.PI / 2.0f)
{
float sampleAngle = theta + a;
float diffuse = Mathf.Clamp01(Mathf.Cos(sampleAngle));
float sampleDist = Mathf.Abs(2.0f * skinRadius * Mathf.Sin(a * 0.5f));
Vector3 weights = Scatter(sampleDist);
totalWeights += weights;
totalLight += diffuse * weights;
a += inc;
}
return new Vector3(totalLight.x / totalWeights.x, totalLight.y / totalWeights.y, totalLight.z / totalWeights.z);
}
public Vector3 Scatter(float r)
{
return Gaussian(0.0064f * 1.414f, r) * new Vector3(0.233f, 0.455f, 0.649f)
+ Gaussian(0.0484f * 1.414f, r) * new Vector3(0.100f, 0.336f, 0.344f)
+ Gaussian(0.1870f * 1.414f, r) * new Vector3(0.118f, 0.198f, 0.000f)
+ Gaussian(0.5670f * 1.414f, r) * new Vector3(0.113f, 0.007f, 0.007f)
+ Gaussian(1.9900f * 1.414f, r) * new Vector3(0.358f, 0.004f, 0.00001f)
+ Gaussian(7.4100f * 1.414f, r) * new Vector3(0.078f, 0.00001f, 0.00001f);
}
public float Gaussian(float v, float r)
{
return 1.0f / Mathf.Sqrt(2.0f * Mathf.PI * v) * Mathf.Exp(-(r * r) / (2 * v));
}
皮肤的红的特性,预积分得到的结果,我们几乎可以完全还原出类似屏幕空间次表面散射的结果。
皮肤的润的特性,如果法线效果很粗糙,从单ramp层级来改变光照的颜色是难以完全抑制住那种粗糙和塑料的感觉的,其实我们还有一个取巧的方法,就是减弱法线的强度,直接减弱细节表现会打折扣,另一种方案则是在强细节贴图法线和模型法线(或者弱化法线的结果,mipmap结果)之间进行插值,来动态减弱法线的强度来达到面部的润的一个表现。当然效果自然不如屏幕空间的卷积那样既可以既保持细节,又有润的平滑表现。
预积分本身的y的曲率,我们看文献本身的卖家秀的表现是很不错的,几乎可以达到很好的y轴曲率变化的表现的,是因为测试的模型面数足够高,因此fwide,ddx,ddy等结果表现会很平滑,而我们手游等模型自然不会有这么细节的表现,结果就会导致曲率变化不平滑,跳变,进而导致面部的光影变化跳变。这是美术同学所不能忍受的,所以我们大概率是不能直接实时计算曲率,但是可以离线计算曲率后,将计算结果多次高斯模糊平滑后的结果存储到mask或者顶点色中来避免由于定点数不足带来的曲率跳变,当然,其实也可以根让美术同学在SP等软件中根据高模制作曲率图或者直接手动绘制一个自定义的mask图来调制y轴的变化,手动控制哪个区域更倾向于次表面。
我们来看一下预积分次表面的效果:
标准Diffuse效果:
屏幕空间次表面散射效果:
预积分次表面散射效果:
可以看到,对于红的特性,预积分的结果和屏幕空间次表面散射的效果几乎差别不大。但是细节法线强度高了了之后润的感觉就不是很明显,预积分更多的还原的是红,而非润。lerp低频法线固然是一个解决方案,但是也无法完全解决如阴影部分的柔和过渡以及细节和润同时满足的表现。
两者的差距实际上是会随着镜头的距离差而逐渐缩小的。如果不是一个镜头bia在脸上的这种,谁又能看得清这么润的表现呢?如果我们的距离是这么远,我们还非得用屏幕空间次表面散射,那其实就是有些杀鸡用牛刀了。额,下图我也忘了哪一个是屏幕空间次表面散射了,哈哈。
自定义次表面散射
试想一个情境,当面临若干个不同的项目,有的项目是超写实的美术风格,有的项目是唯美偏写实的风格,有的项目是唯美偏风格化的美术风格,有的项目是纯风格化的美术风格,多个项目完全不同的美术风格的表现;有的项目处于新项目验证美术风格的阶段,风格波云诡谲,谁也不知道明天会变成什么风格;再或者美术提出了需要完全还原2D手绘的特殊风格的光影表现时,怎么样用一套不加变体的shader来实现这个效果呢?
很不幸,上面几种情况都被笔者这个倒霉蛋碰上了。
来到了这一个阶段,我们所探索的次表面散射,润的特性似乎不是那么重要了。我们更多的关注的是红的特性,也就是皮肤的明暗光影变化的表现。预积分次表面的效果,我们可以观察的是,实际上最为明显的光影变化并非出现在曲率变化大的部分,而是明暗交界线的部分。鼻头耳朵等部分的红润我们可以考虑使用透射的方案进行实现,参考下文透射表现部分,那么,如果宝贵的y轴曲率变化并不明显,我们其实可以考虑把这个轴向另作他用,只用x轴单轴向来计算光照。那空出来的y轴,我们自然可以另做他用。
去掉了y轴变化的预积分图,实际又回归成了传统的基于ramp的光照方案,只是我们要对其稍加改造,让他成为一个适配多风格的高级版ramp功能。首先,我们来罗列一下经历了好几个项目的“摧残”我们收到的美术同学所希望的皮肤:
1)我们希望角色的暗部过渡的软硬是可以调整的,可以硬一点,默认的diffuse太软了,但是又有点不想想卡通渲染那么硬,最好是可以调整的。
2)我们希望角色的明暗过渡的区域是可以调整的,我们希望明面更多一点点,暗面相对少一点点。
3)我们希望角色的明暗过渡的颜色是可以调整的,最好是能拉开一些层次感。
4)我们希望角色的皮肤效果图完全能调整出来我们原画这种手绘的明暗过渡的风格。
要想同时满足以上的条件,标准的预积分显然是难以控制了。但是预积分技术归根结底是Lut技术,和原本的卡通渲染Lut近似。就是用dot(N,L)采样贴图以获得贴图中预存的光照效果。那么,如果我们自己控制x轴采样权重及颜色,自由控制SSS权重及颜色。重定向光照在贴图上的采样范围,形成脸上不同的光感范围表现,我们增加了光的Offset偏移,可以让光过渡范围自定义控制,而背光的颜色也从默认的黑色变成了自定义的颜色。
但是单层的过渡并不足以让我们实现皮肤的颜色的过渡,如果我们把暗部调黑,就缺乏皮肤的红润的感觉;如果调红,就会导致背光面全红,如果是暗面的效果。但是我们想要的是类似标准预积分SSS的中间的偏红过渡带。因此我们可以混合三层上面的效果,而每一层都可以调整光影采样的Offset偏移,颜色,这样我们就可以将面部的明暗对比拉开,分为淡色的颜色渐变层,中间SSS过渡带,尾层暗部背光效果。三层的过渡的范围,颜色全自定义。
现在我们满足了颜色,范围的自定义。那么,这时候美术大哥说了一句,我们的写实的角色,还想带点卡通的硬过渡风格,怎么办?
这时候,我们之前放弃了的2D Ramp图的y轴就派上了用场,我们使用这样一张y轴也有渐变的过渡图,然后每一层采样时通过y轴的偏移来控制y轴的采样位置,就实现了硬过渡和软过渡的动态调节表现。
嗯,经历了一番魔改,把这个shader丢给想尝试八种风格的美术大哥之后,大哥终于满意得自己鼓捣起来了,自此再也没有提过希望变化皮肤的光影表现的需求了。
比如下面两种完全不同的风格只通过微调参数就可以来实现了:
关于纯自定义光影的次表面效果来说,既可以调整成近似标准的预积分SSS效果,也可以实现极端的风格化的皮肤的过渡表现。但是极端自由的同时,带来的问题就是美术难以驾驭。但是这个的确和美术同学的习惯有关,有些美术同学喜欢更自由,而有些美术同学喜欢精简的参数。但是在风格没确定的情况下,一套更加灵活的可以自定义表现的材质更容易帮助美术敲定方案,而我们则可以在TA的同学的配合下使用自定义预积分来协助项目调整出合适的皮肤风格表现,固定预积分的结果然后仅开放给美术同学强度的选项来避免由于过度自由而放飞自我的问题。
关于ramp系列次表面散射的效果无法实现润的表现,我们可以考虑追加在高配展示的条件下,使用屏幕空间次表面散射和ramp次表面散射双拼的方案,用ramp表现皮肤的红光波长更长的散射表现,也就是形成明暗交界带的红润过渡;而使用屏幕空间次表面散射来补充实现更好的蒙皮表现,此时屏幕空间次表面散射的红光散射值可以适当调弱或者保证三色同强度散射。这样高低配下的表现差异不会太大。
至此,我们关于皮肤红润的特性的讨论就结束啦。润和红(皮肤特定的偏红向的明暗过渡)构成了皮肤区别于其他材质最主要的一个特性,也是我们来制作皮肤效果里面最重要的一个特性。屏幕空间,标准预积分,自定义ramp的三种不同的方案,适用的范围自然也是不同的。我们需要根据美术的风格,硬件的性能,展示的距离等多方面的因素综合考虑哪一个才是合适的技术方案。
下面,我们再来看一些皮肤的额外的几个特性,尤其是对于写实风格的皮肤有很大提升的表现。
正常的皮肤自然有非常多的毛孔和细节的表现,虽然现实世界的小姐姐都希望脸上加一个十八级的磨皮滤镜来体现皮肤的好,但是虚拟世界的小姐姐我们反而希望皮肤糙一点,有些毛孔和细节才能体现出皮肤的真实。
因此我们自然会在皮肤上增加一些细节的表现,最简单的其实就是直接使用高精度的法线贴图,即使2048的法线贴图也没有办法在超近距离特写的位置有更精细的精度,这时候我们就可以考虑一下使用细节法线来体现这一效果,在脸上固定的位置平铺Tilling的细节法线。不过这个方案也有一定的局限性,我们仔细观察皮肤会发现皮肤的不同位置的毛孔和纹理的细节是不一样的,如果只使用一种纹理会导致不真实的结果。
这里我们参考了Square Enix的一个思路,那就是在脸上刷地形的方案,使用一张Blend Map混合多张细节法线的结果来作为面部最终的细节法线,这样可以在不同的区域实现不一样的细节效果,同时极大降低了高精度贴图的用量。下面是面部的细节混合图以及超近距离的特写:
在脸上“刷地形”的效果:
动图见链接:https://zhuanlan.zhihu.com/p/571468873
当然,真实的细节更合适糙汉子或者是超写实的小姐姐,如果是唯美的风格,也许细节就没有那么重要了。
高光表现
以上我们完成了基本的Diffuse光照表现,下面我们来看一下皮肤的高光的表现。
由于皮肤分为多个层级,油脂层,表皮层,真皮层,虽然表面的油脂层是最主要的反射的部分,但是如果只是单纯的一层反射,会导致皮肤表面的高光变化简单,而模拟下层表皮层的额外反射高光则可以增加一些皮肤的细节。那么我们就可以用多Specular Lobe来模拟这一现象,通过不同的smoothness来实现双层的高光效果叠加。光照模型可以使用GGX,当然也可以考虑Beckmann这种更贴合角色皮肤的油脂表现,不过如果皮肤细节比较强的情况下,两种光照模型区别不大。
双Specular Lobe也是一个相对于适用于更为写实,细节较强的风格的皮肤方案。
透射表现
皮肤还有一个特性,就是背光通透的表现,与上面预积分次表面散射中我们提到的曲率变化大的部分更红是完全不同的两个概念。背光通透是我们有些特别薄的皮肤的部分,如耳朵和鼻头等部分,在背光照射反方向观察时,会将光线大部分透射开来,甚至超过本身皮肤原始的亮度。
关于透射的实现,我们依然可以采用离线+实时计算结合的方法,我们需要离线生成皮肤的厚度图,来标记哪些位置比较薄来应用我们的透射效果。实时计算时反向光照,根据厚度,阴影等调制得到透射的表现。
透射也是一个倾向于超写实类的效果表现,而且是在背光的角度下才比较明显的特性。
自阴影
还有一个能够大幅度提升角色效果的特性,就是自阴影效果。顾名思义,角色自身投影到自身上的投影,比如头发可以投影到角色身上,有了自阴影可以大幅度增加角色的立体感,否则角色会偏平。但是如果角色走Unity默认的阴影,则会由于精度不足导致盈盈锯齿效果很强,这种情况在越近距离特写的情况下表现越为明显,因此我们需要为角色实现一个独立的投影系统。下图是无阴影,默认阴影,自阴影的效果对比:
原理也比较简单,我们使用一个单独的相机为角色渲染阴影,而这个正交相机的范围刚好只包含角色,就可以让角色阴影贴图的利用率达到最高,进而降低锯齿。
此外,如果我们没有使用屏幕空间次表面的话,就无法对就计算好阴影结果的皮肤整体进行卷积,那么阴影的部分就会有些偏黑显脏,适当的阴影颜色倾向也可以让皮肤的颜色变得更通透,尤其是风格化的皮肤效果:
总结
本文中我们通过不同的技术方案,还原了皮肤的红润,细节,透光,油脂的几个特性。对于重点的皮肤的红润的特性,通过屏幕空间次表面散射,预积分次表面散射,自定义Ramp次表面散射等多种方案实现了针对不同的美术风格的皮肤的表现。其实每一种方案都有他特定的使用范围,如果我们的皮肤占屏比很高,屏幕空间次表面散射自然是不二之选,润的特性极大提升了皮肤的真实性,但是其性能开销和复杂度则要高很多;而预积分系列的次表面散射,接入成本和开销也很低,则更多的适用于低配以及绝大部分游戏的表现,中远景以及性能抠门人士的不二之选;自定义ramp系列的次表面散射则是更多的考虑到如何提升技术的适用广度,让我们的皮肤方案能够更加广泛的的应用到更多的项目。
参考文献
1.GPU Gems 3,Advanced Techniques for Realistic Real-Time Skin Rendering
2.GPU Pro 2,Pre-Integrated Skin Shading
3.Efficient Screen-Space Subsurface Scattering Using Burley's Normalized Diffusion in Real-Time
4.Achieving High-Quality,Low-Cost Skin:An Environment Approach
欢迎加入我们!
感兴趣的同学可以投递简历至:CYouEngine@cyou-inc.com