提起次世代角色的毛发,很多美术的第一反应就是XGen刷一撮曲线,再去Substance Painter(SP)里碰碰运气画几张贴图。但真正能通过项目验收的高阶发片工作流,绝不是“XGen加SP”两个软件各玩各的,而是一条从引导线、卡片网格、烘焙贴图到引擎材质层层咬合的流水线。这几年我经手的项目从写实侧写到风格化二次元,摸过XGen的Interactive Groom,也翻遍了SP论坛里关于发片边缘、Alpha白边、闪烁穿插的求助帖,最后沉淀下来一套相对稳定的组合打法。这套流程最大的价值不是让某一步操作有多炫,而是把“毛发可控”贯彻到了每个环节:镜头里它是能随风飘动的一整片发丝,性能账单上它只是若干张平面的三角形。
这篇文章写给三类人:被毛发测试折磨的游戏美术、刚转行做角色建模想系统性补课的新人,以及想看发片工作流能不能接管影视特写镜头的数字人从业者。我会把XGen出引导线的正确姿势、SP绘制发片贴图的分层逻辑、发片组装穿插的规则全拆开讲,最后再聊聊进引擎之后那些防不胜防的坑。
1. 为什么次世代角色建模里,发片工作流的地位这么稳固
1.1 三种主流毛发方案的本质差异
在聊高阶发片之前,先要把方案选型这件事掰开。现在角色毛发的主流路线就三条:全几何体建模、XGen曲线转管线渲染、XGen加发片(Hair Cards)工作流。定期有人争论“XGen的交互式修饰曲线输出到RenderMan/Arnold多真实”,但那是影视级纯离线渲染的事,跟绝大多数实时游戏项目完全不是一码事。
全几何体建模适合做短毛、卷毛或局部特写,比如一个角色头顶的“寸头感”,用少量体块和法线贴图就能假装过去。它的短板明显——一旦要做长发、刘海、带动态的辫子,三角面数量会迅速爆炸,刷权重时还会为一大片连续网格付出额外的绑定成本。XGen输出原生曲线配Arnold那种方案,在引擎里几乎不可行,因为它会生成海量的曲线几何体,实时渲染扛不住。
发片工作流恰好卡在中间:用平面卡片加透明的毛发贴图模拟发丝,再用多层穿插制造厚重感。它并没有真的去生成几万根曲线,而是用“视觉骗术”让观众产生那是几十万根头发的错觉。实时游戏项目里它几乎是无脑首选,毕竟顶点数可控、材质统一、还能在LOD阶段直接切低密度卡片。哪怕现在UE5的Groom(毛发生成系统)已经能实时跑出不错的John Wick式长发,发片工作流在移动端、开放世界大场景、海量NPC复用这些场景下依旧稳如老狗,本质就是玩家离镜头足够远,性价比说了算。
1.2 外包验收和量产复制的角度:这套流程的投资回报比
从管理角度我也得替美术负责人说一句:纯XGen刷曲线很爽,出图也好看,但交到下游引擎侧就是灾难。曲线动辄几万根,刷代理网格、改碰撞、调稀疏度,每一步都消耗大量人肉工时。发片工作流不一样,它可以拆成标准化工序:引导线放在XGen统一画,卡片贴图放SP统一出,组装和穿插在Maya里按楼层逻辑怼回去,每个环节都能用半自动脚本加速。
之前我带过一版外包测试,对方用XGen的Interactive Groom刷了整整三天的曲线,交付时Maya场景卡到移动一下视口都掉帧。我们拿到之后把描述转成曲线,再按发片流程重做,整个转换半天完成,最终渲染效果反而更好。原因很简单:毛发的视觉断点在投影和光影,曲线生成的那些细碎尾毛,在实时渲染里会被MSAA和TAA吃得七七八八,纯属浪费算力。
所以我现在接任何角色项目,第一件事就是和主美对齐:毛发近景镜头有多少、中远景镜头有多少、角色是主角还是路人。镜头一近,发片密度、卡片层数、贴图分辨率全部上调;镜头一远,直接合并卡片组、减层。这就是发片工作流真正值钱的地方——它让毛发像其他资产一样可以被量化、被拆分、被管理。XGen在这里扮演的是“最高效的引导线生成器”,SP则是“贴图生产工厂”,两件事分开干,反而比硬捆在一起好。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. XGen的正确打开方式:从引导曲线到可用的发片网格
2.1 引导线的前期规划:区域划分决定真实感
很多人打开XGen就直接在头皮上刷连接线,这是最容易翻车的开局。XGen的Interactive Groom是拿来“设计毛发走向”的,不是拿来堆数量的。一张头皮上不同位置的毛发走势完全不同:刘海侧通常向外倾斜,后脑勺向下翻卷,发旋位置有螺旋聚集,鬓角迈向脸颊方向。刷之前必须把头皮按区域拆开规划,我习惯切成额前、左右侧发、顶部后方、发旋、后发底缘五个大区。
分好区之后,每个区单独建一个XGen描述(Description),不要把所有引导线放一个描述里。理由有两个:第一,不同区域的参数差异很大,比如额前需要更多梳理笔刷让发丝垂顺,后发区需要更多Volume让中间鼓起来,一个描述里改参数会互相打架;第二,后期提取曲线做卡片时,如果描述分类清晰,可以直接批量生成几组不同长度、不同疏密的卡片,不用再手工筛选。
刷引导线的小技巧:先低密度刷主线,确定大方向的轮廓,再逐步加线补空隙。XGen的交互式刷子会用Viewport网格做实时反馈,线一多视口就开始卡。真要刷到密度很高的程度,不如刷完主线后用Attributes里的Clumping、Noise这类参数加辅助曲线,让它们在最终渲染时撑体积,而不是真的全部手动画出来。手动画线的意义是“定骨相”,参数化是“增皮肉”,顺序搞反了后期必痛苦。
2.2 提取曲线与卡片网格生成的核心操作
XGen绘制好引导线之后,下一步不是直接拿曲线当卡片去渲染,而是把它们转成多边形世界可以使用的曲线数据。步骤很固定:选中描述,在XGen窗口里执行Generate -> Convert Selected Guides to Curves,这时Outliner会多出一组曲线节点。再用Modify -> Convert -> NURBS to Polygons把曲线变成polygon曲线。这一层的意义是让Maya里的普通多边形工具链接管毛发,不再依赖XGen的Groom运行时数据。
接下来就是把曲线变成真正可用的发片网格。这里有三条路,按可控性排序:
| 方案 | 做法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| XGen原生Primitive | 给描述切换Plane图元,生成带UV的卡片 | 参数化强、一步到位 | 卡片密度和穿插很难精确控制 | 快速试秀、需求较粗糙的阶段 |
| 曲线驱动脚本生成 | 沿每条曲线等距生成四边形平面,由宽度属性控制粗细 | 可控性好,可做长短、宽窄变化 | 需要写Python或借助MASH插件 | 常规游戏角色,最通用 |
| 完全手动卡建模 | 曲线只做参考,在侧视图中手动建卡片摆角度 | 完全可控、能应对特殊镜头 | 工作量巨大、且只适合特写级资产 | 女主长发的过场动画特写 |
我默认大多数项目走第二条路。只要曲线方向是从发根指向发梢,用MASH的Scatter引导或者写一个简单循环,沿曲线每隔一段距离生成一个四边面,让四边面的宽度随着曲线长度递减,就已经能得到很接近真实发丝剪影的卡片雏形。特别提醒:曲线方向必须统一,如果XGen导出时有几根曲线的方向反了,生成的卡片会直接“扭”过去,后期修起来想死。
2.3 卡片UV与区域命名规范
有了卡片网格之后,最大的坑出现在UV上。实线卡片的UV必须严格占满0-1的贴图空间,且卡片的长度方向对应贴图的U向,宽度方向对应V向。这种约定俗成极其重要,因为SP里画发丝时,笔刷的走向会跟着UV方向走。如果某张卡片的UV旋转了90度,贴图里的毛流就横着贴在卡片上,一眼假。
另一个工程化习惯是给不同区域的卡片做ID和命名前缀。前发组可以叫BANGS_A_01,后发组叫BACK_B_05,侧发叫SIDE_C_02。不要觉得啰嗦,当项目里有十几个角色、每个角色几十张发片时,没有分层命名的人真的会把自己逼疯。倒不是引擎需要这些名字,而是人需要,尤其当你和另一名美术协作时,“把BACK组全选加宽一倍”这句话如果没法快速落达,协作效率直接减半。
3. SP绘制发片贴图:发丝走向、Alpha与光影的博弈
3.1 进入SP前的烘焙准备:先解决AO和Normal
卡片网格在Maya里搞定之后,导出成FBX进Substance Painter。这里有一个容易忽略的细节:发片卡片的密度不高,直接烘焙AO会又碎又脏,等于把网格拓扑的缺点放大。我的习惯是导出一份高密度细分的临时网格用于烘焙AO和Normal,再导出一份低模卡片用于最终项目。SP里通过“Maps烘焙”选择高模低模的方式工作,跟常规烘焙盔甲、枪械思路一致。
烘焙的时候开一下Match UV、Envelope等常规选项,但更关键是把Normal贴图设置为Tangent Space。发片是平面,法线贴图主要负责微小的发丝起伏,给卡片增加视觉厚度。如果你用Object Space,一旦卡片在Maya里微调过旋转,法线方向就会错位,高光整个紊乱。切线空间适配性好,后续卡片层级如何穿插都不怕法线打架。
AO对毛发的作用也很重要。发根紧贴头皮的位置应该有明显的闭塞阴影,发梢逐渐变浅。烘焙AO时可以从头皮网格作为“阻挡物”烘焙到卡片上,让发片根部自然产生与真实头皮接触的暗部。这一步没做好的话,后面毛发会显得“悬空”,贴到角色头上像假发套。
3.2 发丝贴图的图层逻辑:不要一张图画到底
真正进入SP绘制环节后,新手最爱犯的错是把整张卡片当成一幅画:先铺底色,再抠发丝,然后滤镜磨皮。这完全是重点错误。发片贴图的使命不是“表现每根头发的颜色”,而是用最少的信息骗过视觉系统。按图层的思路拆分,效果最好:
- 底层(Root Base):头皮附近的深色过渡区,模拟发根阴影和皮质压暗。
- 发色层(Color Variation):大面积的固有色,用Hue和Lightness微调,让不同卡片之间有色差,避免同一色块贴满导致死板。
- 高光层(Specular控制):发丝中段和弯曲处的高光,需要用硬光或者叠加混合模式去画,颜色偏冷白,面积要细碎,不能整片刷。
- Alpha层(Opacity/透明):这个最重要,也是SP中唯一需要单独控制通道的地方。Alpha的完美形态是发根不透明、发梢渐隐、侧边保留少量锯齿状缺口。
很多SP论坛的求助帖都会提到同样的问题:“为什么头发一亮就糊成一片?”十有八九是高光层刷得太亮太宽,或者Alpha边缘没有渐变。高光应该顺着UV的U向画,像一条细线走在长发片的1/3高度处,接近发梢处逐渐减淡甚至消失。没有渐变的高光会让卡片边界在引擎里像一块塑料。
3.3 Alpha是发片工作流的胜负手
Alpha通道决定的是“哪里透明、哪里不透明”,而在毛发材质里,几乎所有的质量崩溃都发生在Alpha边缘:白边、锯齿、半透明排序混乱、边缘闪烁。我在SP里画Alpha的习惯是先用一张渐变灰度当作基底,保证发根实、发梢虚;然后在这个渐变的边缘区域用发丝笔刷随机划出密密麻麻的“碎缺口”。这些缺口不需要多规整,越乱越自然,它们的真实作用是让卡片边缘不是一条平滑的透明曲线,而像几百根发丝参差错落的剪影。
如果卡片太宽且Alpha边缘太直,模型在动态镜头里会不断“闪现”平面感。解决工具就是这些小锯齿。另外Alpha贴图的分辨率必须匹配卡片的体积,贴在屏幕上占200像素的头发如果只用512贴图,Mipmap一降级,Alpha锯齿立刻原形毕露。资产生成时前发这种大区域建议直接刷到2048或以上。
SP论坛里还有个高频话题是“导入引擎后边缘一圈白边”。根源一般是Alpha贴图在被引擎采样时产生了半透明到全透明的阈值截断,边缘像素残留在RGB里却没有对应Alpha。处理办法是绘制RGB时把靠近边缘的像素压暗,或者输出贴图之前对Alpha做一个2像素左右的内缩(Erode),让透明边缘的RGB信息整体退到不可见范围。别指望引擎侧去修正,贴图层面把边缘打死是最省心的。
4. 发片组装的核心法则:层次、穿插、发际线处理
4.1 三层发片结构:底层、中层、表层不能混
贴图做完,所有卡片要回到Maya里组装,这一步决定毛发是“蓬松有体积”还是“一层薄纸”。我几乎对所有角色都采用三层结构:底层(Base)紧贴头皮,密度最高,主要职责是兜住头皮阴影和填洞,防止头发飘起来时露馅;中层(Mid)遮盖底层的拼接缝隙,颜色略浅,长度适中;表层(Coverage)负责视觉主体,长度最长,密度最低,颜色最亮,因为玩家首先看到的就是表层的大轮廓和受光面。
这三层不是同一套卡片复制三次。底层的卡片应该更宽、更短、朝向更贴头皮;中层的卡片要开始做出弯曲和转折,部分卡片的Alpha尖端要自然“虚掉”;表层的卡片要拉长,且可以适量做一些向外翻卷的曲线。如果三层全用同一张发片贴图,最终渲染时所有卡片看起来都是同一片“塑料扇子”,毫无体积差。一般做法是底层使用较脏、较暗的一套贴图,表层使用颜色偏亮、高光更强的一套,这样配合HDR光照,发丝马上会有层次。
4.2 发片穿插规则与视觉穿帮的规避
发片做的是“拼接”而不是“平铺”,穿插是存在目的:让视觉上无法分辨单张卡片的边界。但穿插不是乱插,有两条硬规则。第一,卡片和卡片之间必须在Z方向有明显错层,同一层内尽量少做完全平行的叠放;完全平行、同高、同样大小地放十张卡,Alpha边缘一旦被光照直射,就会暴露“一整排扇子”。第二,穿插要朝头皮法线方向压,尤其发根位置,要保证视觉上每一缕头发都是从“头皮某个点”长出来的,而不是浮在头皮上方1厘米的草丛。
镜头动态时还有一种穿帮:卡片快速转向镜头,透明区域和实心区域发生大面积翻转,毛发看起来厚度破功。规避办法是减少单张卡片的宽度和面积。宁可多放几张窄卡片,也别一张大宽片贯穿整个后脑勺。窄卡片的翻转被邻卡遮挡,视觉连续性还在;宽卡片一旦旋转角度大于30度,整个轮廓都会凸现出来。
4.3 刘海、鬓角与发际线的差异化处理
发际线是最能决定角色气质的地方,也是最容易穿帮的地方。我的经验是单独给发际线区域建一个“发际线卡片组”,长度短、宽度窄、Alpha渐变更长。贴图里发际线处应该有一条“头皮阴影”过渡带,让短发和皮肤之间不是硬生生的一条半透明切线。
刘海的处理要注意“分组”而不是“排排站”。国内许多角色的刘海是五五分、三七分的翘向,如果直接生成一排等宽卡片,刘海最外沿会像帘子一样横切额头。适当让中间几撮长一点、两侧短一点,并在发稍加卷曲,才是自然。鬓角则要特别注意长度收敛,真正的头发从鬓角处是逐渐变短并贴近面颊,如果卡片在这一带还保持着后发的长度,角色瞬间就会变成“长发毛盖”。
5. 进引擎前的最后一道关:材质设置与常见画质问题修复
5.1 引擎里的材质参数:Masked还是Translucent
卡片从Maya导出FBX进入UE或Unity之前,工程层面的第一道选择是透明模式。当前实时引擎里做透明毛发的主流做法就是Masked(透明遮罩)和Translucent(半透明)两种。Masked通过AlphaClipThreshold把Alpha低于阈值的像素直接裁剪掉,优点是深度排序稳定、不受透明物体相互穿透的影响,缺点是阈值一旦过高,发梢的细碎锯齿轮廓会被整体“咬掉”,看起来像被啃过。Translucent保留半透明渐变,发梢过渡更柔和,但排序问题严重,遇到另一件半透明物体或自身交叉时就会闪。
我的默认推荐是Masked加Dithered Opacity。Dithered Opacity利用棋盘格抖动在远处过渡成半透明,能保留发梢轮廓又基本不依赖深度排序。如果不支持Dithered,还可以用TAA的Alpha通道后处理,这正是很多次世代游戏的隐藏技巧。贴图侧同时把AlphaThreshold控制在0.3到0.5之间,具体数值要反复测,直到发梢边缘不消失、亮面不穿帮为止。
| 问题 | 症状 | 处理方式 |
|---|---|---|
| 边缘闪白 | 毛发轮廓出现一圈白线 | 贴图侧压缩Alpha边缘并做Erode |
| 镜头越拉远发丝越稀疏 | Mipmap降级导致小面积Alpha被裁剪 | 开放更高Mipmap Bias或给发丝加宽度 |
| 两层卡片交叉时闪烁 | 深度排序冲突 | 改Masked或开启Dithered Opacity |
| 背面法线导致高光怪异 | Double Sided开启后背面犯病 | 使用Two-Sided Sign法线节点或改用Single Sided加卡厚度层 |
5.2 混SP论坛时最常见的几个坑:汇总成问题排查表
发片工作流社群里提问量最大的问题,其实不是制作过程,而是“做出来了,进引擎就崩”。我列一个排查表,所有坑都亲身踩过且验证过有效。
- AlphaThreshold太高导致发梢消失。解决办法是降阈值或给卡片的Alpha贴图增加发梢灰度值。
- 双面渲染打开后高光发黑。根源是Tangent Space法线只有正面方向,背面法线反向导致光照计算异常。改用Two-Sided法线或分离内外卡组分别赋予正向法线。
- 发片之间因为深度测试产生“闪烁的裁衣剪刀痕”。这属于排序问题,先把所有卡片改成Masked模式,不行再把相邻层卡片用材质参数Material Depth Offset稍微做偏移。
- 发丝颜色在HDR场景下发灰。多数情况是贴图采样了sRGB而引擎默认了一部分线性空间,检查引擎贴图色彩空间配置即可。
5.3 最终打磨:用LOD和通用贴图库给整个工作流提速
一个完整的次世代发片工作流在交付阶段还要考虑性能预算。卡片在Maya里可以拆成LOD0、LOD1、LOD2三层,LOD0保留全部层数和卡片数量,LOD1去掉底层只留中层加表层,LOD2直接把卡片数量砍半。因为发片本身是平面,LOD切换通常没有明显的轮廓跳变,比起常规Hero资产友好得多。
最后分享一个让我省过大量时间的习惯:维护一套属于你自己团队的“通用发片贴图库”。当你把底层、中层、表层的SP源文件整理成模板,发色改色只需要动Color层,Alpha完全不动,再配合“XGen刷引导线 -> 曲线生成卡片 -> 套模板贴图”的半自动链路,一个新角色的头发从零到进引擎基本可以压缩到两天以内。这个工作流真正成熟的标准,不是你能把某根发丝画得多像,而是你能在有限工时内稳定地产出符合镜头要求的毛发资产,这才是次世代项目里最稀缺的能力。
