图形引擎实战:移动平台海飞丝系统-流程篇
大家好,我是搜狐畅游引擎部的TA Marth,毕业来畅游已经快一年了,一直在和puppet_master负责海飞丝系统的项目。今天来给大家分享一下海飞丝系统毛发制作的流程。
前面两篇对于海飞丝系统的渲染,运动进行了详细的讲解,相信大家已经对海飞丝系统有了一定的了解,如果还不太了解海飞丝系统,可以先去看一下前面的运动和渲染篇。
这篇文章主要介绍从毛发模型制作流程技巧和对模型的优化。
视频见链接:https://www.zhihu.com/org/sou-hu-chang-you-yin-qing-bu
传统方法
传统的发片渲染一直是比较主流的制作方案,直到现在,它依然是绝大部分游戏采用的方案。它的优势就是性能好,能用比较少量的网格制作出效果比较好而且有层次的头发。其实传统发片流程已经能做出来比较真实的头发了。但是缺点就是它因为是发片,所以运动起来不够真实,甚至因为怕穿帮,都不会让头发进行大幅度的运动。
主要制作工具
发丝流程相对于发片流程制作方式差别较大,发片可以进行手摆,但是发丝可不行,一根一根种头发丝可真是要累死人。好在Maya提供了相应的毛发制作模块Xgen,还有ephere的Ornatrix插件,Ornatrix功能非常强大,支持Maya,3DSMax,C4D多个平台。
但是我们这里选择使用Maya的Xgen哈哈哈,两者相对于这一套流程来说都能满足基本的功能,Xgen因为是内置于Maya内的模块,不用单独下载,会更方便一点。
Xgen
Xgen制作毛发不再是发片的方式,而且基于引导线去生成头发。这样以少量的引导线去生成的方式看似节省了制作难度和时间,但是如果想要做的完成度高,造型完整还是需要花好多心思。
Xgen本身还分为两个系统,交互式Xgen修饰和Xgen描述。
交互式Xgen修饰交互式
Xgen修饰类似一个对于头发的雕刻系统,可以用笔刷对头发直接产生影响,比较直观,就像是梳头发。缺点就是对于一些复杂的长发,编发。交互式Xgen修饰很难直接做出一个比较好的效果。
交互式Xgen修饰的雕刻层类似于PS的图层或者是3DSMax的编辑方式,可以在一层的操作之上进行另外一层操作,而每层互不影响。这种编辑方式也可以在很多软件中看到,Ornatrix也是基于这种编辑方式。
Xgen描述
Xgen描述就是通过少量的引导线生成大量的头发,我们可以通过控制引导线的造型来控制整体头发的造型,优点是引导线比较好控制,可以制作复杂的长发,编发造型。造型好控制。缺点就是有些时候所见非所得,因为头发是通过引导线插值生成的。不过我们可以通过一些技巧来避免这些问题。
这两个系统各有优点,我们在制作过程中都会用得到,主要使用引导线制作发型,交互式修饰作为辅助。
发型制作难点
发型制作的难点主要就是两部分。一个是复杂发型本身的难度,制作比较耗时麻烦。另外一个就是顶点数,根数和段数,属于制作优化的部分。后面我们将从两个部分来讲我们在制作优化方向趟过的坑。
不同造型
不同发型给我们带来的效果和性能之间的差异还是比较大,不难想象不同长度和不同复杂度的造型所需要的段数是不一样的。在制作中,我们需要足够的段数才能还原我们想要的造型。所以长发相对短发就需要更多的段数。而且不仅是在造型阶段,后面的运动阶段如果想要更流畅的效果,也需要足够段数支持。
短发
短发其实是相对比较容易的,长度会比较短,所需要的段数不会太多,造型也不会特别复杂。能够用稍微少一点的段数还原出造型。
短发的性能理论上会更好一些,所以我们在测试的初期也是从相对短的头发开始进行尝试的。
长发
长发相对于短发会比较困难,因为长发的长度比较长,所以需要的段数就要更多才能保证相对完美的造型和运动。而且这个段数针对这个长发发型的,很难进行优化,就算再怎么优化,也需要保证长发的造型和运动。如果顶点数是固定的话,段数这个顶点数就需要从头发的根数上去优化,减少根数,增加段数,保证总的顶点数持平或者少于总顶点数。
减少根数很简单,但是随之带来的秃头问题该怎么解决?
而且长发往往也会拥有更复杂的造型,比如卷发,这样的头发就更难搞,因为需要单根头发的段数比较多才能有一个比较好的效果。我们在初期也制作了一个中长卷发。在当时看来效果并不好。
特殊造型
头发特殊造型的头发不光会有本身长度的变化,还会有一些特殊的造型,比如马尾,双马尾,还有各种盘发之类。像这种一般制作起来会更繁琐。这样的头发一般会需要分区制作。虽然制作起来可能会繁琐,但是在性能上有可能会比较省,因为这种马尾的根部到发圈的位置是几乎不动的,所以我们可以用相对较少的根数来制作,而且也几乎不会参与运动。
但是天底下总有更困难的事,有这样一个发型经常被称为“死亡发型”。
这个发型和上面马尾的区别就在于上面的马尾是扎得比较紧实的,根部到发圈部分完全可以不用动,所以既省了头发根数,也省了运动计算。
但是这个发型从根部到发圈的头发是相对比较松动的,所以既要解决它的根数问题也要解决它的运动问题。并且因为被束起来了,所以运动逻辑和普通的散发也会不一样。真是“死亡发型”。
因为想要让这个系统能够支持所有的发型,我们也主动挑战了这个发型。
当然还是会有其他类型特殊发型,比如脏辫。这种发型我们目前还没有尝试过,感觉主要的难点在编发的段数和每支辫子和头发的连接上。不过从造型来看,这种发型已经脱离了发丝想要表现的感觉,因为头发都是扎起来的。用发片制作也许效果会更好。
制作流程要点
这一段我们主要谈制作技巧,具体的软件操作不会讲的特别细。主要讲一些思路。其实Xgen制作发丝模型的原理非常简单,就是通过在头皮上种Xgen的引导线,控制引导线的造型,生成发丝,最后转成mesh导入引擎。
但是在制作过程中难免会遇到一些不理解的地方。
引导线用法
比如我们会以为这个引导线非常智能,可以随便刷几条就能生成我们想要的发型。
哈哈哈看起来似乎并不智能,我们是想要一个短发的造型,但是它似乎只在头顶上的范围长头发,而且看右图,头发之间出现了穿插,这是由于引导线插值导致的,因为这一块的头发没有引导线控制,所以只能对上面我们种的已有的引导线进行插值,而正常这个地方的造型不应该是这样。所以就会出现穿插。
每根引导线都会控制一块头皮范围内长出来的头发,离着引导线越近,就会越接近引导线的造型。离着引导线比较远的,就会通过两个相邻引导线进行插值计算,如果两个引导线离着过远,有些位置就会插值出我们并不想要的头发造型,所以如果想要精确控制每一个小范围,就要不停的加引导线。引导线越多,整个发型就会控制的越细腻。
解决办法就是在已有引导线下面种上新的引导线,让新的引导线引导造型不正确位置的头发,让他们有一个“老大”。并且按照真实头发造型,让下面的引导线被压在上面的引导线里面,尽量不超过上面的引导线。右图可以看到,新增引导线的位置的穿插明显改善。但是下面又出现了穿插。这也是相同的问题。
从这个现象我们能够猜到,Xgen的引导线并没有那么“智能”,能够支持我们用几根简简单单的引导线就做出我们想要的造型。而是需要尽量所有的地方都有引导线控制造型才能让造型完整细腻。我们看一下“死亡发型”。
这个引导线看起来比上面的引导线多了很多,并且确实是一根一根刷的。但其实也并不是所有地方的引导线都很密,露在外面的头发需要更细腻的造型表现,引导线就可以密一些,盖在里面的头发不一定能看见,引导线密度就可以稍微疏一点。
如果希望头发的造型完成度更高更细腻,密密麻麻的引导线肯定是躲不过的。
不同造型的优化及分区
上面的发型类型各不相同,有些复杂造型我们不得不用比较多的段数去塑造。所以顶点数优化的重任首先就落到了头发根数上。我们为了用最少的头发根数去实现看起来比较多的头发效果。在制作发型上会尽量把头发根数用在“刀刃”上。
既然是用在“刀刃”上,我们做出来的头发密度绝对不是均匀的。可以举一个简单的例子,一个发型可能会存在发缝,发缝的位置(红色)一般会比较容易显得稀疏,所以我们可能把发缝的位置(红色)密度提高。除去发缝其他的位置(蓝色)就可以生成低密度的头发。
蓝色区域降低密度之后,就需要增加头发的宽度来提高覆盖率,因为蓝色区域一般是盖在下面的,所以适当提高宽度也不会对效果有太大影响。
还可以再来看一个例子,有时候我们制作的发型会有很多部分,这样的发型迫使我们将头发分组制作,这样制作起来也比较好控制头发的走向。我们也可以根据不同的分组来赋予不同的密度。
比如刘海部分(红色)的生长区域比较大,而刘海(红色)一般我们又想让它比较轻薄,我们就可以把密度调低。披肩发部分(绿色)理论上生长范围会比较大,但是我们为了制作方便,只让他从绿色的范围里生长,这样头发的密度就会不够用,就需要适当提高密度。而束发部分(蓝色)因为是固定住的,几乎不会参与运动,所以我们可以把它的生长区域减到最小,这样也能避免穿帮。
以上两种方式都可以尽量把头发根数用在比较“重要”的地方,我们也可以结合两种方式来优化。缺点就是会增加美术人员制作头发的繁琐程度,做一个复杂的头发会分好多组。
头发浓密度优化
根据上面的理论。可以来看一个实际的例子。正常人的头发有10万根,如果想让正常人的长发流畅飘动,每根头发至少要有15段。15*2*10w=300w这个数量级,移动端可没有那么好驾驭。
但是如果头发的根数少,效果可想而知,就是会秃头。。可以看到这个发缝特别稀疏明显。这就是减少根数带来的后果。不过解决方法很简单。我一般会在发缝的位置再单独种一层头发。这样就能很好解决发缝的问题。而且因为他只有一点点的生长范围,所以不会增加太多的根数。
不过即使是这样,也难免会有因头发太稀疏而看到头皮的情况。这种情况也很经典,其实在发片制作流程中也会有这样的情况,因为想要营造头发的透气感,外层的头发会用头发比较稀疏的贴图,为了避免看到里面的头皮。美术人员会把发片分为好几层,最里面的一层是颜色比较实比较厚的发片,或者直接在面部贴图上头顶画上头发的颜色。
发丝制作我们也沿用这种方式来解决露头皮的问题。
效果还不错,并且在后期,我们还可以对标记头发,让引擎内对头发的粗细分别进行控制,因为我们需要内层的头发提高覆盖率,想让外层的头发拥有更多透气感。
头发段数优化
除了头发的根数,每根头发的段数也是无法忽略的。如果一根头发的段数过低,是无法保证造型的,在运动的表现上也不会太理想。段数越高,圆弧就会越完美。
所以我们需要在段数和效果之间进行权衡,首先想到的就是直接在Xgen里修改CV数。但是直接修改CV数会出现问题,因为Xgen描述的毛发是通过引导线插值生成的,如果CV比较低,生成出的毛发可能会严重偏离引导线的造型。直接修改CV数能达到优化效果有限。
但其实并不难想到,如果我们进行段数优化的话,一定是优先减掉直线上的段数,尽量保留曲线上的段数,这样能让造型变化不大。
所以可以在把毛发转成Mesh之后进行减面,这样可以避开引导线插值,能尽量让毛发贴合引导线造型。
因为Maya内没有类似的功能,所以就自己简单写了一个减面的工具。减面工具的基础命令是利用了Maya里的收拢边命令。
遍历每根头发,然后每次选择角度最小的边收拢。但是这样容易把一个地方的段数减得特别少,所以还要在减面的时候额外添加一个段长度的约束,这样能够避免段数密度失衡。
两张图的发丝片的朝向在转Mesh的时候可能有些不一样,这不重要。可以看到,从Mesh状态减面就不会破坏之前造型。
所以在制作过程中可以先在Xgen中用稍微高一些的CV数匹配引导线造型,转成Mesh之后再用减面工具减到一个合适段数。
不过可以看到,减面之后的面片棱角的感觉相对更明显,所以具体要减多少段数,还是需要多尝试,因为减多了也会损失造型的精度,并且影响运动的表现。
这多多少少能够节省出来一些段数。
调整造型导出
当我们做完引导线和头发的造型之后,虽然我们需要把引导线种的比较密集,但是相对与头发丝来说还是比较稀疏的,而且因为引导线之间的插值,我们很难做出那种非常细的细节。对于发型来说,这种小细节代表着完成度。
当然我们可以通过分描述来单独做这么一根避免其他引导线的插值。这也是一种方式。但是描述多起来调节参数难免就会比较麻烦。Xgen还有另一个系统我们说会用到的:交互式Xgen修饰。
在做完Xgen描述部分之后,确认好没有什么需要改的了。就可以利用转化为交互式梳理这个功能来转为交互式Xgen修饰系统
因为交互式Xgen修饰系统可以用笔刷直接对头发进行雕刻,我们可以用它来修型和增加一些细节。这不会改变头发的段数,只影响头发造型。
可以利用冷冻工具冷却其他的头发,然后单独调整需要调整的头发。这样就不会影响其他的头发。
调整完之后头发会多一些细节,但是之前的问题也还是存在,因为头发局部拉伸,发丝的棱角感可能会加强,所以在调整的时候要注意。
然后如果想把这些头发导入引擎需要把这些毛发转为Mesh,利用这个工具来转为Mesh。
然后导入引擎之后会识别每一根头发的一条顶点数据,根据顶点在引擎里生成发丝。
扩展
进到引擎后我们还可以进一步提升效果。例如通过标记头发让哪些头发更粗,哪些头发更细。或者通过标记控制头发之间的杂色,让头发的发丝感更强,也能控制多个颜色实现挑染的效果。
总结
本篇文章介绍了移动平台海飞丝系统制作流程的一些思路和遇到一些问题。简单介绍了制作发丝模型的工具,不同造型的区别,引导线的用法,不同造型的分区优化,以及最后的调整造型导出。目前的方案不是很完善,还是有很多值得优化的地方。不管怎么说我觉得这是一次成功的探索。让我们都觉得在手机上实现发丝运动成为可能性,随着手机性能的提高。移动海飞丝也一定会成为手游的标配。
欢迎加入我们! 23届春招已经开启啦,等你投递~
内推码:NTAI1kh