【译】Blacksmith中的皱纹贴图

发表于2016-02-11
评论2 1.8k浏览

原文地址http://blogs.unity3d.com/2015/05/28/wrinkle-maps-in-the-blacksmith/

原文作者未做版权声明,视为共享知识产权进入公共领域,自动获得授权

在我们筹备The Blacksmith短片项目的时候,我们从未真的考虑过将自定义皮肤着色器提升到足以成为一个专门工作。不过,我们还是想看看能否用一些我们能做的简单方式,让挑战者的表情更生动。在头脑风暴之后,我们決定为项目添加一個驱动皱纹纹理的形状融合(blendshape)

 

为了给表情加上深度和细节,我们确信如果能让皱纹同时作用法线和遮挡, 采用标准著色器(Standard shader)将会给出最棒的效果。同时,我们也希望能通过某种方法,来对特定的脸部表情表达加以限制。

 

皱纹贴图驱动设计

我们创建了一个专门的组件,使得动画器(Animator)能够定义皱纹层,网格(Mesh)中的每个形状融合都各自对应一层。皱纹层的定义包含了纹理贴图、强度指示器以及一组匹配于人脸各部分的遮蔽权值。因为使用了遮蔽权值,每一个具体的皱纹层都可能作用于1~4个面部区域,并对每个区域造成不同程度的影响。




因为我们希望能够在任意给定的时间混合多达四个不同的表情,在任何情况下,单单混合就需要用到11个纹理采样(两个基础纹理,八个细节纹理和一个遮罩纹理)。对此,唯一切实选择,就是将皱纹贴图在一个屏幕外的预渲染通道中组合起来。我们发现ARGB2101010渲染纹理格式在此非常切合我们的需求,因为它允许我们仅用10bit通道中的两个来处理法线,从而剩下的一个用于存放遮蔽信息。在每一帧,皱纹贴图组件都会寻找出四个最具影响的形状融合,然后更具权值分层渲染。


一旦我们在屏幕空间内完成所有的皱纹数据合成,剩下的唯一要做的事情就是:重定向我们用于绘制人脸的标准着色器的法线和遮蔽数据的输入。在实际操作中,这仅需在表面着色器(surface shader)的主函数中添加很少几行代码:


// Sample occlusion and normals from screen-space buffer when wrinkle maps are active
#ifdef WRINKLE_MAPS
float3 normalOcclusion =
tex2D(_NormalAndOcclusion, IN.screenPos.xy / IN.screenPos.w).rgb;
o.Occlusion = normalOcclusion.r;
#ifdef _NORMALMAP
o.Normal.xy = normalOcclusion.gb * 2.f - 1.f;
o.Normal.z = sqrt(saturate(1.f - dot(o.Normal.xy, o.Normal.xy)));
#endif
#endif



最终结果


极度愤怒表情下,对比原基础头部和皱纹贴图在满权重呈现下所带来的额外细节。



我们还额外编写了多种调试输出模式,使我们能够轻松地查看完全融合的遮蔽和法线贴图。这有助于定位各个组件在最终结果中究竟起何作用。





Take it fora spin


我们已经把这一功能单独抽离到了一个示例项目,你可以从Asset Store下载


 


它仅含维京挑战者的头部,带有两个我们在Blacksmith短片中用到的表情,不过对于启迪你在自己的游戏中应用皱纹贴图而言,这应当已是一个相当不错的开头了




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