新版“峡谷第一美”妲己尾巴毛发制作分享

关于作者:梁家斌,腾讯互动娱乐天美工作室群高级游戏美术师。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第1张图片


之前有很多人来询问新版妲己宝宝
毛茸茸的尾巴 做法,
先谢谢大家对这个毛发效果的认可,
我在这里就简单的分享一下,
毛发的实现思路和制作方法。

毛绒材质在生活中出现的频率非常高,
但是在各种游戏中,
我们却很少看到这种材质效果的良好表现,
原因在于它们的制作与渲染成本都太高了。
所以, 实时毛发渲染
是业内最为期待的次世代特效之一。

我们先看看这些材质的特征:
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第2张图片

[ 毛茸茸的衣服 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第3张图片

[ 可爱的毛绒玩具 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第4张图片

[ 毛茸茸的动物 ]


他们有着柔软的丰富的外轮廓、
柔和的光影、温暖,
这种材质表现一直是女孩子所喜爱的。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第5张图片

[ 微观的毛发,其实可以理解为一根根的圆柱体,越细毛发的质感越柔软 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第6张图片

[ 无数细小的圆柱体拼合在一起,就形成了我们看到的皮毛效果 ]


因为毛发复杂性与庞大的计算量
(每根毛发产生的阴影遮挡),
所以在毛发渲染方面,
基本一直都是离线渲染的专利。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第7张图片

[ MAYA毛发渲染 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第8张图片

[ 迪士尼《疯狂动物城》毛发渲染 ]


直到最近,
GPU处理能力才达到实时计算毛发的标准,
当然那也是针对PC平台而言,
我们手机暂时还望尘莫及。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第9张图片

[ Square Enix 夜光引擎的毛发 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第10张图片

[ 插片-毛发制作 ]


我们一般游戏的毛发渲染,
都是将毛发纹理放到模型面片上面,
用AlphaBlend或者AlphaTest剔除镂空区。

但这两者也都无法尽善尽美:
-AlphaBlend没有深度会有模型穿插问题。
-AlphaTest有顶点深度但边缘锯齿感严重,
需要在SSAA下面才不会有明显的锯齿。
-两者结合使用效果比较好,
但会带来更高的性能消耗。

所以至今为止,
游戏上面都很难做到满意的毛发表现,
尤其是手游,
往往我们只能从设计层面去规避这些问题。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第11张图片



要制作一个东西,
我们必须抓住它的特点。
那么毛发有哪些特征呢?
我稍微归纳了一下:

通透性-次表面散射:
毛发是非常的细小的,
光线很容易就可以穿透它的表面,
尤其是浅色毛发,
颜色越深吸收光线的能力越强,
所以深色发毛的透光性相对较低。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第12张图片

[ 不同颜色的毛发通透性差异 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第13张图片

[ 逆光下的深色头发与浅色头发 ]


这也是为啥很多女孩子
比较喜欢染发、烫发的原因之一。
因为浅色比黑色的毛发,
在逆光下的效果要漂亮很多。
烫发可以使头发蓬松,
让更多的光线穿透与反弹,
这样整体的层次感会变得很丰富。

复杂的遮蔽性:
毛发又非常的密集,
毛发相互之间的阴影遮挡造成毛发。
密集的地方光线也很难继续渗透进去,
就形成了发根到发梢的阴影渐变。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第14张图片

[ 毛发的Occlusion ]


特殊的高光-各项异性高光:
头发的表面并不是光滑的,
上面有一层被称之为毛鳞片的结构,
产生的高光散射性很高,
很多人造毛很难做到这一点。
这也是为啥很多廉价的假发的质感
让人一眼就看出来不真实的原因。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第15张图片

[ 显微镜下的头发 ]


上面我们说了头发,
是排列在一起的一个个细小圆柱体。
很多人不理解为什么
我们要把头发的高光叫做各项异性高光,
我用一张图简单说明下。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第16张图片

[ 各项异性高光的产生 ]


我们这里提到的所谓各向异性高光,
其实是我们没办法真的将头发
用一个个圆柱体来渲染,
而使用一种基于观察近似的算法模拟结果。

而动物的短毛皮比人类头发更加复杂,
可以大致分为两类,
一种是表层的长毛(被毛),
另一种是内层的绒毛(更加细小、弯曲)。

丝绸同理但更加复杂,
不同的丝本身质感就不一样,
加上不同针织结构,
如纱、绮、绢、锦、罗、绸、缎等10多类,
造成丝绸效果最终质感有很大的差异性,
有兴趣可以深入了解不同丝绸的微观结构。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第17张图片



说了这么多。
在手机游戏里怎么实现这些效果呢?
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第18张图片


用顶点细分来制作不现实,
这么大量的毛发,
又是移动端平台,
机器的计算性能达不到要求。

而用大量面片插片的方式,
会占用大量3D美术的人力成本,
尽管效果是很好,
相对效果来说也不太划算。

最后选择了美术制作上最简单的
多pass渲染的方案。
因为这套方案在美术资源制作上,
基本上和普通角色资源没有差别,
唯一的限制就是skin多边形数量上的限制。

而且这套方案在PC端游上已经比较成熟,
比如《剑灵》。
多pass的方法局限性也很大,
不过我们可以拆分开来研究和优化。

layer实现方式
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第19张图片

[ 多pass的实现方式 ]


根据模型使用层 (layer) 来渲染毛发长度,
在 Unity Shader 中,
每一个 Pass 即表示一层。
当渲染每一层时,
使用法线将顶点位置挤出模型表面 。
Pass及使用的层数越多渲染效果越好,
当然开销也越大。
这种做法如果想要很好的表现,
就需要大量的pass。
如何用少量的pass实现更好的效果,
后面我们再一步步解决。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第20张图片

  1. float3 aNormal = (v.normal.xyz);
  2. aNormal.xyz += FUR_OFFSET;
  3. float3 n = aNormal * FUR_OFFSET * (FUR_OFFSET * saturate( v.color.a )); //顶点色alpha通道控制毛发扩展范围
复制代码


然后将Noise贴图根据layer做衰减,
来当做alpha值。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第21张图片

[ Noise贴图 ]

  1. _UVoffset ("UV偏移:XY=UV偏移;ZW=UV扰动", Vector) = (0, 0, 0.2, 0.2)
复制代码


一定加入基于layer层高度的UV偏移。
• 没有UV偏移效果的毛怎么看都会像刺猬。
• 记得对毛发做UV偏移的时候,
   Diffuse贴图的UV也要跟着一起计算哦。
 

  1. float2 uvoffset= _UVoffset.xy  * FUR_OFFSET;

    uvoffset *=  0.1 ; //尺寸太大不好调整 缩小精度。

    float2 uv1= TRANSFORM_TEX(v.texcoord.xy, _MainTex ) + uvoffset * (float2(1,1)/_SubTexUV.xy);

    float2 uv2= TRANSFORM_TEX(v.texcoord.xy, _MainTex )*_SubTexUV.xy   + uvoffset;

    o.uv = float4(uv1,uv2);

复制代码
  1. half3 NoiseTex = tex2D(_SubTex, i.uv.zw).rgb;

    half Noise = NoiseTex.r;

    color.rgb = lerp(_Color,_BaseColor,FUR_OFFSET) ;

    color.a = saturate(Noise-FUR_OFFSET) ;

    return color;

复制代码


也可以加入风力、重力等顶点控制项。
根据不同性能的机器来选择是否开启。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第22张图片

[ 默认:顶点重力:UV偏移 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第23张图片

[ Noise混合 ]


也可以将多层Noise
混合到一起来做一些不同的毛发,
将他们分别放到R、G、B不同的通道里,
可以减少贴图量。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第24张图片


缺点:
• 这样大家能看出来,
  多pass的制作方式,
  无法制作头发这样的长毛,
  只能制作较短的毛发。
  不过我们这次的目标也是制作短毛,
  所以长毛与头发可以先抛开。

• 要有比较好的效果,
  就需要非常多的pass来进行计算,
  这也是我们不希望的。
  因为移动平台对大量Overdraw这样的
  像素级处理是非常大的一笔开销。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第25张图片

[ layer30 : layer10 ]


layer的层数是越少效率越高的,
在低layer上得到更好效果是我们的目标。
我将控制半透明毛发的曲线做了一些优化,
勉强可以在低layer上面达到多layer的效果。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第26张图片

[ 对Alpha的衰减曲线做调整 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第27张图片

[ layer30 : layer10 : 拟合曲线后的layer10 ]


优化Layer数量

一般的做法:

  1. alpha = Noise -FUR_OFFSET;
复制代码


优化后:同时加入了可控的变量。

  1. alpha = (Noise*2-(FUR_OFFSET *FUR_OFFSET +(FUR_OFFSET*FurMask*5)))*_tming ;
复制代码


灯光

到现在为止,
在外形上基本接近了我们想要的毛发效果。
我们还需要将毛发的渲染特征也加上去。
这里用3个部分来实现:
环境光、轮廓光、太阳光

环境光:
环境光可以是一个单色,
也可以是一个微弱的顶底渐变,
或者球协光照(提取Hdir贴图低频数据)。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第28张图片

[ 这里可以根据 手机游戏账号转让平台 不同项目的需求来定义 ]


这里以简单的顶底颜色为例:
 

  1. float3 normal = normalize(mul(UNITY_MATRIX_MV, float4(v.normal,0)).xyz);

    half3 SH = saturate(normal.y *0.25+0.35) ;

复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第29张图片

[ 无环境光遮,与真实效果差异很大 ]


前面讲了毛发的特点之一
就是环境光遮蔽与自阴影,
缺少了环境光遮蔽的效果只能打20分。
环境光遮蔽形成的散射是带有颜色的,
会根据物体的颜色不同产生不同颜色。
我很懒,就没将颜色与环境光遮蔽
之间的关系公式写进去,
直接开放一个颜色手动设置反弹的颜色。
(也能节约一些计算不是~)
 

  1. half Occlusion =FUR_OFFSET*FUR_OFFSET; //伽马转线性最精简版

    Occlusion +=0.04 ;

    half3 SHL = lerp (_OcclusionColor*SH,SH,Occlusion) ;

复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第30张图片

[ 无环境光遮 vs 加上环境光遮蔽 ]


但要记住固有色越浅,
反弹光就越强,
Visibility的影响就越弱;
反之颜色越深,
反弹光就越弱,
Visibility的影响就越强;
简单的说就是:
物体的颜色越浅,AO颜色越浅;
反之颜色越深,AO颜色越深。

轮廓光:
轮廓光其实也是环境光的一部分。
这里单独给轮廓光计算,
也只是弥补环境反光的不足,
同时加一些可控项,
也可以调出一些特殊的不一样的效果。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第31张图片

[ 毛发轮廓光 ]


同时也和上面的一样,
物体的颜色越浅,
轮廓光穿透率越强;
反之颜色越深,
轮廓光穿透率越弱。

这里也一定要加入环境光遮蔽的遮挡,
因为毛发的透光性,
边缘稀疏的部分光线穿透率更高。
同时模拟了在环境光下次表面散射效果。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第32张图片

[ Fresnel :Fresnel+Visilibity ]


差异性在低多边形下会更加明显。
 

  1. half Occlusion =FUR_OFFSET*FUR_OFFSET; //伽马转线性最精简版

    Occlusion +=0.04 ;

    half Fresnel = 1-max(0,dot(N,V));//pow (1-max(0,dot(N,V)),2.2);

    half RimLight =Fresnel * Occlusion; //AO的深度剔除 很重要

    RimLight *=RimLight; //fresnel~pow简化版

    RimLight *=_FresnelLV *SH; //加上环境光因数

       SHL +=RimLight;//与环境光结合

复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第33张图片

[ 模型线框:Occlusion平方:Occlusion4四次方 ]


将Occlusion的计算
放到RimLight平方的前面,
是因为模型的多边形数量低,
轮廓会比较明显。
将Occlusion4次方,
能更好的减弱低多边形的影响。
因为我们用于毛发材质的模型面数,
是非常非常低的,
如果模型面数相对高一些的模型,
可以放到后面。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第34张图片

[ 环境光最终渲染结果 ]


太阳光:
我们平常说的太阳光,
其实可以把它看成是平行光。
太阳其实是个点光源,
不过因为它过于庞大,
光线到地球上面的夹角非常非常小,
再到我们的可视物体的时候,
就完全可以忽略掉了。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第35张图片

[ 太阳为什么是平行光 ]


我们就取最简单的公式。
 

  1. half3 lightDir = -_SGameShadowParams.xyz; //外部传入的灯光方向

    half NoL =dot(lightDir,normal);

    half DirLight =NoL * _FurDirLightExposure*_DirLightColor;

复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第36张图片

[ 正测光:背光 ]


普通光照模型这样计算没有问题,
但完全没有毛发的特性:
缺少太阳光在边缘的穿透性,
也没有逆光下的毛发次表面散射效果。
缺少每根毛产生的复杂的阴影表现。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第37张图片

[ 阴影与光线边缘的穿透 ]


用一个最简单的拟合就可以得到这个效果。
主要利用了NdotL(-1~1)的特性。
 

  1. _LightFilter("平行光毛发穿透",  Range(-0.5,0.5)) = 0.0

    half3 lightDir = -_SGameShadowParams.xyz;

    half NoL =dot(lightDir,normal);

    half DirLight= saturate (NoL+_LightFilter+ FUR_OFFSET ) ;

    DirLight *=_FurDirLightExposure*_DirLightColor;

复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第38张图片

[ 正测光:背光 ]


最后将所有光照合并到一起:
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第39张图片

新版“峡谷第一美”妲己尾巴毛发制作分享_第40张图片

[ 佩奇陪你过大年 ]


• 为了节省性能,
  所有灯光与颜色计算全部在顶点空间完成;
• 像素空间只用来计算贴图采样;
• 很多需要贴图一起计算颜色值的地方
  都优化省略掉了,比较遗憾。
• 所有颜色计算都是在线性空间进行的
  所以最后要转换到伽马空间,
  这一步也可以去掉,
  也可以再加上简单的tommping,
  让画面颜色变得更好。

高光 - Anisotropic(各项异性)
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第41张图片


前面讲毛发特性的时候,
对各项异性高光做了个简单的介绍。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第42张图片

[ Anisotropic(各项异性) ]


学术上Anisotropic(各项异性)的解释:

• 某些材质上有一些微观上有方向的细丝,
  这些细丝在宏观角度来看是不易察觉的,
  典型的有光盘的背面或者是头发。
• strand based anisotropy是
  对上述光照情形的一种建模。
(http://www.bluevoid.com/opengl/sig00/advanced00/notes/node159.html)

一些Anisotropic表现的例子:
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第43张图片

[ 《崩坏3》 ]

新版“峡谷第一美”妲己尾巴毛发制作分享_第44张图片

[ 《爱丽丝惊魂记:疯狂再临 (Alice: Madness Returns)》 ]


各向异性制作的各种具体实现方式
我就不一一细说了:
 

[ 沿着法线方向去偏移切线 ]

  1. float3 TShift(float3 tangent,float3 normal,float shift)

               {

                   return normalize(tangent + shift * normal);

               }

复制代码

[ Anisotropic高光 ]

  1. float StrandSpecular(fixed3 T,fixed3 V,fixed3 L,fixed exponent)

       {

           float3 H = normalize(L+V);

           float dotTH = dot(T,H);

           float sinTH = sqrt(1- dotTH * dotTH);

           float dirAtten = smoothstep(-1,0,dotTH);   

           return dirAtten*pow(sinTH,exponent);

       }

复制代码


用抖动忒图来弥补头发细节。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第45张图片

[ 抖动贴图制作头发高光细节 ]


头发比较特殊
观察头发的高光会发现,
其中一层高光是有颜色的,
另外一层高光是没有颜色的,
且两层高光的相互错开一点点。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第46张图片

[ 观察头发高光 ]

[ 头发双层高光公式 ]


我们根据公式在VS里计算出高光效果。
这时候会发现高光效果会很粗糙,
简直有点不堪入目。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第47张图片

[ 顶点 VS 逐像素 ]


一步一步来优化。

• 依然使用上面已经使用老套的方法,
  用FUR_OFFSET做高光的遮蔽后,
  因为VS渲染精度方面过低的问题缓解了,
  但效果方面依然不是太好。

fixed SPec1 =StrandSpecular (T1,V,L,_specExp.x)*FUR_OFFSET;
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第48张图片

[ 高光加入FUR_OFFSET对比 ]


• 因为毛束是一个个细小的单个圆柱体,
  它的高光也并不是一个平面连续的表现。
  我想了很多方法来弥补毛发体积与细节。
  最终下面的结果相对来说,
  得出的结果是目前得出的最好的。
  大家猜一下——下面这张图是怎么得到的?
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第49张图片

[ color = Alpha平方 ]


其实这就是我们目前的alpha当做色彩输出的结果。

• 越靠近透明的区域越黑,中间区域偏亮。
• 它刚好能达到我们高光缺少的细节部分的要求。

我就用它来当做单根毛发边缘体积的遮挡。
得到的结果很不错。
同时这个也替代了抖动贴图。
 

  1. color.rgb +=i.Specular  * (Noise*Noise);
复制代码

新版“峡谷第一美”妲己尾巴毛发制作分享_第50张图片

[ 加入Noise遮罩,代替抖动贴图方案 ]


加入低频与高频2层高光后的效果更加自然。
 

新版“峡谷第一美”妲己尾巴毛发制作分享_第51张图片

[ 双层高光效果 ]

  1. fixed3 T1 = normalize(_specExp.z*normalWorld+binormalWorld);

    fixed3 T2 = normalize(_specExp.w*normalWorld+binormalWorld);

    fixed SPec1 =StrandSpecular (T1,V,L,_specExp.x) *FUR_OFFSET;

    fixed SPec2 =StrandSpecular (T2,V,L,_specExp.y) *FUR_OFFSET;

    o.Specular  = SPec1*_SPColor1  + SPec2*_SPColor2;

复制代码


高光部分我测试了很多方案,
目前效果只能说还能凑合着用,
因为都是在VS进行的计算,
效率上面应该还行。


第一次写分享,
罗里吧嗦的写了一大堆。
效果方面肯定还有非常大的优化空间。
欢迎大家一起讨论和指正。

一些个人遇到的问题:

• 毛发UV控制部分我加入了flowmap,
  但是FlowTex的绘制太困难,
  而且也不直观。
  可以做个工具实时直观看到flowmap
  在毛发上面的绘制效果。
  甚至可以直接在unity绘制到模型顶点色
  XY2个值上面控制毛发方向。

• 多模型重叠的时候还是有深度穿插。
  分享一个16年的国外视频,
  用了另一种方案来控制毛发长度与方向。

·END·

你可能感兴趣的:(java)