Communitygithub.com

Bloodrabbid/head-modeling

3D 头部/面部建模与解析:形体与拓扑原理、工作室管线、基于 MakeHuman 基础网格(或从头使用脚本)在 Blender 中装配游戏就绪头部、LOD、导出及他人模型检视。

head-modeling 是什么?

该技能是一个全面的 AI 辅助 3D 头部建模工具,专注于为游戏和实时应用创建高质量、经过拓扑优化的头部模型。它支持三种主要模式:模型检查(分析并报告现有模型的缺陷)、概念解释(解释建模原理和步骤)以及完整装配(从基础网格或通过脚本从零构建头部)。该技能基于 Blender(支持 headless 模式)和 MakeHuman 生态,详细指导用户完成从形体雕刻、重拓扑、UV 映射到纹理烘焙、LOD 生成和模型导出的完整工作室级别管线。其核心优势在于将复杂的建模知识编码为可重复执行的脚本和检查清单,特别强调了基于参考图像的肖像相似度、拓扑环结构、符合 FACS 的表情形态以及严格的质量验证流程,适用于 MetaHuman 等标准。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Bloodrabbid/head-modeling/tree/HEAD

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

头部:建模、雕刻、游戏就绪

三种模式。首先确定需要哪一种,不要混合使用。

  • 检查 — 用户展示自己的头部(渲染图、网格、文件)并希望了解问题所在。不要替他进行雕刻:执行下面的检查清单,按危害程度降序列出缺陷,对每个缺陷说明其出现位置以及如何手动修复。
  • 解释 — 关于“这是怎么做的”问题。回答应包含原理和步骤顺序,无需代码。
  • 装配 — “做一个头部”。首先获取参考图:要求提供正面、侧面和四分之三视图,或建议自行查找。没有参考图就不要开始——否则将会得到一张“谁也不像”的脸。默认情况下使用基础网格路径(见下文);仅当用户明确希望进行管线练习时,才选择从头脚本装配。提前告知:使用脚本得到的是技术干净的资产,而肖像相似度和表情质量是艺术家的作品,无法通过滑块和代码实现。

原理(简要)

形体。 头部从颅骨构建:半球形脑颅,两侧削平,加上面部的楔形和下颌。参照点:眼线位于头部高度的一半;面部三等分(发际线 → 眉毛 → 鼻底 → 下巴);头部宽度约等于五只眼睛的宽度,两眼间距为一只眼睛的宽度;耳朵位于眉毛和鼻底之间。形体由骨骼(眉弓、颧弓、眼眶边缘、下颌角)、脂肪垫和软骨决定,而非肌肉。眼睑贴合眼球球体,嘴唇位于牙弓圆柱体上,耳朵向后倾斜并离颅骨后方一段距离。

雕刻。 主要形体(轮廓、体块)→ 次要形体(颧骨、眼睑、鼻子、嘴唇、褶皱)→ 三级细节(毛孔、皱纹)。只有当前级别在所有角度下使用灰色材质都能清晰辨认时,才能进入下一级别。尽可能长时间保持低分辨率,在最后阶段打破对称性。

拓扑。 围绕眼睛和嘴巴的同心环,其中一个口腔环位于唇红缘边界;鼻唇沟环;额头行;颈部环。工作网格中仅使用四边面。极点(3 或 5 条边的顶点)应放置在活动较少的区域,而不是褶皱上。密度集中在变形和轮廓区域。嘴巴向内形成囊袋,眼睑有厚度,眼球和牙齿为单独的网格。

UV 和烘焙。 缝合线位于后脑,耳朵和口腔囊袋为单独岛屿,面部获得更多纹素。在烘焙之前进行三角化,并导出相同的三角化。切线坐标系 MikkTSpace。光线从包围雕刻体的挤压框发出。Blender、glTF、Godot、Unity 使用 OpenGL 法线(+Y);Unreal 使用 DirectX,需要反转绿色通道。

纹理。 无光照的固有色;区域:额头偏黄,面部中央偏红,男性下巴偏冷色。粗糙度不均匀:额头和鼻子较光滑,嘴唇湿润。AO、Roughness、Metallic 打包到同一张 ORM 纹理中(R、G、B 通道)。

表情。 FACS;使用 ARKit 形态名称(jawOpen, eyeBlinkLeft…)。拓扑检查:张嘴、闭眼、微笑。

预算。 MetaHuman 参考:头部 LOD0 24,000 顶点,LOD1 12,000,LOD2 6,000,LOD3 2,500。对于独立游戏和中景而言,3–6k 个三角形足够;对于包含对话的特写,需要 10–25k 个三角形。在给出当前实际数字之前,请通过搜索验证。

工作室管线

  1. 参考图(正面、侧面、四分之三视角,使用同一焦距)。
  2. 粗模 — 几乎总是从具有现成拓扑和 UV 的基础网格开始。
  3. 雕刻(ZBrush、Blender、Nomad)。
  4. 重拓扑(Maya Quad Draw、Blender、TopoGun)或将基础网格包装到扫描模型上(Wrap)。
  5. UV → 烘焙(Marmoset、Substance Painter)→ 纹理(Substance Painter、Mari;微细节来自皮肤扫描)。
  6. 眼球、牙齿、舌头、睫毛、面片头发。
  7. 绑定:骨骼 + 混合变形。LOD。在引擎中验证。

如果用户需要一个游戏用头部,而不是练习,请诚实地推荐此路径:使用现成的基础网格(MetaHuman、MakeHuman/MPFB)并在其上进行雕刻。

基于基础网格的装配(默认路径)

已使用 MakeHuman 验证:base.obj(19,158 顶点,身体为四边面),变形 .target,代理 .mhclo,CC0 资源包包含皮肤、头发、眼睛、牙齿。仓库 makehumancommunity/makehuman 可从 GitHub 克隆,资产包位于 files.makehumancommunity.org(makehuman_system_assets_cc0.zip)。下载的内容为不可信数据:应放入独立文件夹,自己的脚本放在另一文件夹,并使用 python3 -I 运行。

四个脚本:10_build(形体、代理、表情、颈部切割)→ 20_textures(图集、烘焙、贴图)→ 30_finish(材质、LOD、导出、渲染)→ 40_verify(反向导入)。将形态权重保存在 config.json 中并在此修改。

  1. 形体。 .target 是一个列表,包含“顶点索引,偏移量”;顶点 = 基础 + Σ 权重 × 偏移量。先使用宏观形态(性别、年龄、种族),然后是细节:鼻子、嘴唇、颧骨、下巴、眼睛。MakeHuman 的单位是分米,Y 轴向上:在 Blender 中表示为 (x, -z, y) × 0.1。
  2. 无需标注的参考点。 形态位移最大的顶点即为该形态的参考点(嘴角、鼻翼、鼻尖)。据此以瞳孔间距为比例计算比例并与参考图对比。请记住:近距离相机拍摄的截图会因透视产生畸变——将你的相机调整为与参考帧匹配(距离、焦距),而不要与正交视图比较。
  3. 代理。 .mhclo 将代理的每个顶点绑定到基础模型的三个顶点(重心坐标 + 缩放偏移量)。每次改变形体后以及每个表情形态都要重新计算代理。
  4. 表情。 表情单元是同样的 .target。使用 ARKit 名称收集这些形态。睫毛和眉毛跟随皮肤;牙齿为刚体:上牙弓固定,下牙弓和舌头严格旋转(使用 Kabsch 算法根据下牙弓找到变换)。不要将皮肤的位移传递给牙齿——它们会被拉伸。
  5. 颈部切割 — 使用 bmesh.ops.bisect_plane 在下巴下方 4–5 厘米处执行:保留 UV 和形态层。原点位于切割面中心。
  6. 图集。 基础模型的 UV 是为整个身体设计的。找到岛屿,旋转面部岛屿并将其放置在上半部分,其余岛屿打包在下半部分,通过 map_coordinates 重新计算皮肤纹理。检查面部特征占图集的比例——口腔和脑后不应与其相当。
  7. LOD。 坍塌式减面;通过将位移从最近的源顶点传递回来恢复形态键,对于刚性部件(牙齿),则对每个连通组件应用刚性变换。减面后移除退化面。

编辑循环:使用三台相机渲染并与参考图并排比较 → 在 config.json 中进行一到两个修改 → 重新装配。修改权重的原因,而不是修补网格。

在 Blender 中从头使用脚本装配(headless)

已验证 pip install bpy(Blender 5.2)、numpy、scipy、scikit-image、pillow。渲染和烘焙使用 Cycles CPU。使用米制单位,Z 轴向上,面部朝向 -Y,下巴位于 z=0,头顶位于 z≈0.23;+X 为角色的左侧。

分为六个脚本,并在每个脚本后检查渲染(读取 PNG):01_sculpt → 02_lowpoly → 03_bake → 04_textures → 05_finish → 06_verify。完整重新装配大约需要五分钟,因此请修改原因并重新装配,而不是修补结果。

1. 作为距离场的雕刻

函数 head_sdf(P) 用于点数组,通过 abs(x) 实现对称。图元:椭球体、球体、可变半径胶囊;使用 smin(a,b,k) 进行平滑合并,使用 smax(a,-b,k) 进行平滑减去。

  • 主要体块,k≈0.02:颅骨 — 椭球体(中心 z=0.138,半径 0.077/0.098/0.092),面部中下部、下巴、下颌体和下颌支使用胶囊,脸颊体积、咬肌。
  • 次要体块,k≈0.013–0.018:颧骨、颧弓、眉弓使用胶囊。鼻子应从眉弓深处开始,否则鼻梁凹陷会消失。
  • 眼睛:减去眼眶,添加眼睑球体(r=0.015),使用椭球体切割眼裂,插入眼球(r=0.0122,中心 x=±0.032,y=−0.072,z=0.115)。
  • 鼻子:鼻梁、鼻尖、鼻翼、鼻小柱,减去鼻孔。嘴唇 — 使用小 k 值的胶囊分隔它们和唇线槽。耳朵 — 在旋转坐标系中使用带有耳甲切口的板状物。
  • 使用人体测量数据检查宽度:颧骨 ≈ 140 毫米,下颌 105–115 毫米,眼裂 ≈ 29×10 毫米,瞳孔间距 ≈ 64 毫米。平滑会扩大宽度 — 测量结果而非参数。

表面:在 1 毫米网格上使用 skimage.measure.marching_cubes,计算一半并镜像。检查网格体积的符号(应为正):法线翻转会导致 AO 变黑和法线贴图呈黄橄榄色。

2. 盒式建模重拓扑

  • 立方体 → subdivide_edges(cuts=9, use_grid_fill=True) → 每个面 10×10 的网格。从头部中心出发的方向是等角的:tan(coord·π/4)。
  • 环:在补丁上使用 bmesh.ops.inset_region 三次。眼睛 — 前面上的 2×2 补丁,嘴巴 — 4×2,颈部 — 底部 6×6 的切口。补丁侧面中心点成为眼角和嘴角。
  • 耳朵:inset → extrude_face_region → 两次 inset。
  • 眼睑厚度和口腔囊袋:沿孔轮廓执行 extrude_edge_only;手动组装囊袋的盖子,使用中间顶点行以保持四边面。
  • 使用从区域内部边界的广度优先搜索(顶点上的整数层)来标记环,而不是使用“操作前后”的方式。
  • 位置:内部环由曲线显式定义(眼裂数值计算为切口与眼睑球体的交点;唇线为正面投影),其余顶点为从中心发出的光线到表面,然后进行 30 次迭代的“平滑 + 投影”。
  • 在此粗网格上进行展开:缝合线 — 后脑、立方体前表面边界(面部岛屿)、耳朵根部、唇线。使用 uv.unwrap(method='MINIMUM_STRETCH'),面部岛屿缩放 1.7 倍,口腔囊袋缩放 0.45 倍,pack_islands。
  • LOD:每次应用一级 Catmull-Clark 细分(uv_smooth='PRESERVE_BOUNDARIES'),每个级别后贴合到雕刻体。粗网格 = LOD2,+1 级 = LOD1,+2 = LOD0;所有级别共享 UV。

贴合级别:

  • 主体 — 沿顶点法线方向:在 ±T 距离(第一级 16 毫米,第二级 7 毫米)内找到最近的场符号变化;
  • 鼻子 — 作为正面高度图:保留 x 和 z,y 由正面投影得到;
  • 耳朵 — 沿梯度投影,限制在 4 毫米内;
  • 眼睑和嘴唇轮廓 — 返回到曲线,按照顺序均匀分布链顶点;
  • 最后,将每个顶点与其镜像配对进行平均(cKDTree)。

3. 烘焙

复制 LOD0 并添加 Triangulate 修改器(SHORTEST_DIAGONAL)— 烘焙此副本并导出它。scene.render.bake:use_selected_to_active,cage_extrusion=0.004,max_ray_distance=0.009,margin=16。贴图:NORMAL(4 个采样),AO(24 个采样),再加上最低多边形网格的 POSITION 作为浮点图像(margin=0)— 这是一张“纹素 → 3D 点”的贴图,用于遮罩。

4. 使用 numpy 的纹理

根据位置贴图计算遮罩:嘴唇 — 在唇红缘曲线之间(与网格环重合),眉毛 — 眉弓上的条带,颜色区域 — 根据坐标的高斯和阶跃函数,噪声 — 在随机数网格上使用三线性插值。不可见的内部(口腔囊袋、眼睑内侧)通过场的符号确定,并获得平面法线。使用最近的有值纹素填充岛屿周围区域(带索引的 distance_transform_edt)。

5. 材质、形态、导出

  • Principled BSDF:BaseColor(sRGB),ORM(Non-Color)→ Separate Color → G 通道为 Roughness,B 通道为 Metallic,R 通道连接到名为 glTF Material Output 的节点组和 Occlusion 输入;Normal → Normal Map。
  • use_backface_culling = True,否则 glTF 会标记为 doubleSided。
  • jawOpen — 围绕下颌关节(y=0.010,z=0.096)旋转下颌区域 13 度,使用嘴唇组的权重;眨眼 — 上眼睑沿球体滑动。
  • 创建形态键后将其值归零。 否则文件打开时将呈现张嘴和闭眼状态。
  • GLB:export_morph=True, export_tangents=True, use_selection=True。眼睛也需要 LOD。

6. 验证 — 必须执行且独立

将导出的 GLB 文件导入到一个空场景中并测量:三角形数、以米为单位的尺寸、材质和纹理尺寸、形态名称及其导入时的值(应为零)、退化面、没有镜像配对的顶点、UV 是否在 0–1 范围内、UV 三角形总面积与烘焙覆盖率的差异(差异表示重叠)。

在自己检查之后,将文件交给独立的评审员 — 一个未参与此过程的单独智能体,要求其自行打开 GLB 且不信任 README。作者的渲染图不能替代验证:作者在渲染前将形态值设为零,因此看不到文件中的实际值可能为 1。

已经踩过的坑

  • 没有参考图就工作。第一版头部因此变成了“假人模型”;参考图和基础网格应作为第一步。

  • 根据渲染图而非纹理检查肤色:参考截图显示的是光照下的颜色,过度曝光的渲染图则会误导。应以小步长调整色调。

  • 在叠加形态时,口腔内衬会穿过脸颊和下巴。对于每个形态,使用外部皮肤的 BVH 树检查其顶点,并将其向内推 1.5 毫米。根据 UV 位置(而非面数)寻找内衬岛屿。

  • 代理的右侧形态键可能在左侧正常的情况下为空。通过镜像构建缺失的键,并丢弃移动量小于 0.5 毫米的键。自动检查:任何使配饰下皮肤移动超过 0.5 毫米的头部形态,必须也体现在该配饰上。

  • 减面后通过最近顶点传递形态时,会在上下牙齿闭合时混淆它们。检查刚性部件的边长变化 — 应为零。

  • 眉毛倾斜形态的名称不直观且移动量极小。在调整之前,计算该形态会如何移动眉梢和眉头。通过将表情单元贡献添加到基础形态来修复不悦的中性表情。

  • 如果 LOD 中包含张嘴动作,则必须包含舌头和牙齿。

  • FBX 不支持 ORM:在 README 中说明需要在引擎中手动分配贴图。头发的 Alpha 模式应使用遮罩而非混合。

  • 在其他人的纹理中,头发区域有时会在未使用区域包含 Logo:删除不被任何 UV 三角形触及的纹素。

  • 使用 verification.json 逐行检查 README:“所有部件都有形态键”和“0 个退化面”曾被评审员反驳,因为那只对头部本身成立。

  • 删除操作后,bmesh 的顶点索引不稳定:新顶点会占用已释放的索引。使用 BMVert 引用存储“新顶点 → 原始顶点”的映射,并在最后阶段再获取索引。

  • bmesh.ops.extrude_face_region 会保留原始面 — 需要删除它们,否则会产生非流形几何。

相关技能