PMX 骨骼名称对照这件事,说白了就是把模型里那一堆日文假名、汉字、罗马音混排的骨骼名,翻译成你自己看得懂、工具认得出、脚本匹配得上的统一体系。做过 MMD 模型改造、动作移植或者把动捕数据往回灌的人都知道,骨骼名对不上,动作就是零零散散掉一地,脚在原地打滑,手臂像脱臼一样扭着,裙子该飘的时候纹丝不动。它解决的从来不是"翻译"这么简单的问题,而是让动作数据、物理运算、IK 链、追加变形这四套机制能在同一个模型上正常对话。适合谁看?如果你正在做模型改模、想把 A 模型的动作套到 B 模型、或者准备写脚本批量处理 PMX 文件,这份对照表能帮你省掉大量反复试错的时间;如果你只是好奇 MMD 模型内部长什么样,看完也能大致明白那些日文骨骼名各自负责哪块身体。
1. PMX骨骼命名到底乱在哪:标准方言与三种写法并存
骨骼名称混乱不是谁偷懒,而是历史叠出来的。PMX 格式本身只规定"骨骼有个名字字段",但没规定这个名字必须叫什么。于是从 MMD 早期版本一路发展下来,形成了官方标准骨、准标准骨、各家自制骨三层结构,再加上日文、汉字、英文三种写法同时流通,才变成了今天这个样子。理解这三层结构,比死记硬背对照表有用得多,因为你会知道遇到一个陌生骨名时该往哪个方向猜。
1.1 官方标准骨骼与准标准骨骼的分层逻辑
MMD 官方(VPVP 相关规范)给出的标准骨骼,是最小可用集合,包括全ての親、センター、上半身、首、頭、肩.L/R、腕.L/R、ひじ.L/R、手首.L/R、下半身、足.L/R、ひざ.L/R、足首.L/R以及各手指骨。这一层是所有模型都必须有的,缺一个动作数据就会掉帧。
准标准骨骼是在标准骨基础上扩展出来的一层,用来弥补标准骨做不出精细变形的问题。典型成员包括グルーブ、腰、上半身2、肩P.L/R、腕捩.L/R、手捩.L/R、足D.L/R、ひざD.L/R、足首D.L/R、足先EX.L/R、両目、つま先IK.L/R。这些骨不是必须的,但绝大部分动作数据作者会用到,尤其是上半身2和腕捩,少了它们,上身弯曲和手臂扭转就会明显失真。
第三层是模型的私有骨,比如スカート_0_1、髪_1_2、胸.L、尻、リボン这类,全看模型作者怎么起名。这一层没有统一标准,也是移植动作时最容易出问题的地方——动作作者根本不可能知道你裙子分几节、每节叫什么。
注意:判断一个模型"骨骼全不全",不要看骨的总数,而要看准标准骨缺了哪些。总数两百的模型可能缺
腕捩,总数八十的模型反而可能是精修过的标准骨集合。
1.2 三种命名派系的由来与市场现状
日文假名混汉字派是当前主流,VPVP 标准模型和绝大多数现代模型都走这条路。特征是把ひじ(肘)、ひざ(膝)、つま先(脚尖)写成平假名,而腕、首、頭、足首写成汉字。为什么不统一?因为肘和膝这两个汉字在日文语境里容易被其他字形混淆,早期作者为了区分就写成假名,后来成了事实标准。
全汉字派多见于旧模型和部分国人作者作品,肘.L、膝.L直接写汉字。这类模型在 MMD 里用没问题,但很多自动匹配脚本按标准名写死的字典就匹配不上,需要额外做一层别名映射。
英文名派通常在english_name字段里填arm_L、elbow_L这种,本地名字段还是日文。真正把本地名也写成英文的模型多半是从 Blender 或 Unity 转过来的,这类模型在 MMD 里加载后骨骼面板会显示英文,编辑时反倒是件好事。
1.3 PMX文件里其实存了两个名字字段
这是很多人做了几年模型都没注意到的细节:PMX 的每根骨骼有两个名称字段,一个是本地名(name),一个是通用名(english_name)。MMD 本体读本地名,部分导出工具和游戏引擎读通用名。所以你看到一个模型在 MMD 里骨骼显示日文,导出到 Unity 后变成英文,不是被自动翻译了,而是换读了另一个字段。
这个机制带来一个非常实用的技巧:做模型改造时,如果你不想动本地名(怕破坏原作者的物理和动作兼容性),可以只填通用名字段,让下游工具链用英文名工作。反过来,如果你想做一份跨语言的骨骼对照,直接批量导出这两个字段就是一张现成的对照表,比手工整理靠谱得多。
2. PMX骨骼名称对照表:按身体分区逐段拆解
下面这几张表是我自己做改模时整理的版本,覆盖标准骨和准标准骨,中文叫法用的是圈子里比较通用的说法。有些叫法在不同群里会有差异,我尽量选了歧义最小的那个,同时在备注里说明了容易踩的误解点。
2.1 躯干与头部区对照
| 标准日文名 | 中文习惯叫法 | 常见英文名 | 父骨 | 备注与常见误解 |
|---|---|---|---|---|
| 全ての親 | 全部之亲 / 总父级 | all_parent | 无(根骨) | 模型唯一的顶层根骨,整体位移、整体旋转都靠它 |
| センター | 中心 | center | 全ての親 | 实际控制重心,走位、转身用它而不是用根骨 |
| グルーブ | 节奏骨 | groove | センター | 上半身和下半身的共同父级,扭腰动作的关键 |
| 腰 | 腰 | waist | グルーブ | 准标准骨,缺它时某些动作的腰部扭动会变僵硬 |
| 上半身 | 上半身 | upper_body | グルーブ | 脊柱下段,弯腰用它 |
| 上半身2 | 上半身2 | upper_body2 | 上半身 | 准标准骨,脊柱上段,挺胸、侧弯靠它 |
| 首 | 脖子 | neck | 上半身2 | 有些模型父骨直接是 上半身,没有 上半身2 |
| 頭 | 头 | head | 首 | 注意不是"首",日文里"首"是脖子 |
| 目.L / 目.R | 左眼 / 右眼 | eye_L / eye_R | 頭 | 不是所有模型都单独分左右眼 |
| 両目 | 双眼 | both_eyes | 頭 | 由左右眼骨骼驱动,控制视线朝向 |
这里必须强调首和頭的区别,我见过不止一个人第一次看到骨骼列表时把首当成头骨,然后怎么调模型都不对。日文的"首"(くび)指的是脖子,"頭"(あたま)才是脑袋。同理手首是手腕不是手,足首是脚踝不是脚。
2.2 手臂与手指区对照
手臂区的坑主要在捩り骨和手指编号上。捩り(ねじり)骨是扭转补偿骨,靠"追加变形"机制把父骨的一部分旋转量传导过来,让前臂在扭的时候不出现"糖纸效应"。
| 标准日文名 | 中文习惯叫法 | 常见英文名 | 父骨 | 备注 |
|---|---|---|---|---|
| 肩.L | 肩 | shoulder_L | 上半身2 | 锁骨位置,耸肩、含胸 |
| 肩P.L | 肩P | shoulder_p_L | 上半身2 | 准标准骨,作为 肩.L 的父级,避免肩部变形冲突 |
| 腕.L | 上臂 | arm_L | 肩.L | 就是大臂,日文"腕"泛指手臂 |
| 腕捩.L | 上臂扭转 | arm_twist_L | 腕.L | 准标准骨,有的模型会拆成 腕捩1/2/3 |
| ひじ.L | 手肘 / 小臂 | elbow_L | 腕.L | 汉字派写作 肘.L |
| 手捩.L | 手腕扭转 | wrist_twist_L | ひじ.L | 准标准骨 |
| 手首.L | 手腕 | wrist_L | ひじ.L | 注意父骨是 ひじ 不是 手捩 |
| 親指0.L | 拇指根 | thumb0_L | 手首.L | 只有拇指有 0 号,其他手指从 1 开始 |
| 人指1/2/3.L | 食指三节 | index1/2/3_L | 依次相连 | 汉字派写作 人差指 |
| 中指1/2/3.L | 中指三节 | middle1/2/3_L | 依次相连 | 最稳定、最常被动作数据使用 |
| 薬指1/2/3.L | 无名指三节 | ring1/2/3_L | 依次相连 | 日文"薬指"即无名指 |
| 小指1/2/3.L | 小指三节 | pinky1/2/3_L | 依次相连 |
手指这一块有个很实际的问题:动作数据里做"抓握"动作时,通常只驱动中指1、人指1、薬指1、小指1和親指0,靠权重和物理把剩下的关节带过去。所以如果你的模型手指骨命名对不上,表现不是整只手不动,而是手指伸得笔直、像在拍证件照。
2.3 腿脚与IK区对照
腿部是误解最严重的区域,没有之一。日本语境的足在骨骼体系里指大腿,ひざ虽然字面是膝盖,但这根骨实际承担"小腿"的角色,它一转,整条小腿跟着走。
| 标准日文名 | 中文习惯叫法 | 常见英文名 | 父骨 | 备注 |
|---|---|---|---|---|
| 下半身 | 下半身 | lower_body | グルーブ | 髋部,和 上半身 分家 |
| 足.L | 大腿 | leg_L | 下半身 | 不是"脚",是大腿根到膝盖 |
| ひざ.L | 膝盖 / 小腿 | knee_L | 足.L | 汉字派写作 膝.L |
| 足首.L | 脚踝 | ankle_L | ひざ.L | |
| つま先.L | 脚尖 | toe_L | 足首.L | 部分老模型没有这根骨 |
| 足先EX.L | 脚掌前端 | toe_ex_L | 足首.L 或 つま先.L | 准标准骨,用来做脚掌弯曲、脚趾抓地 |
| 足IK.L | 脚IK | leg_ik_L | 全ての親 | 注意 IK 是全角字符,写成半角会匹配不上 |
| つま先IK.L | 脚尖IK | toe_ik_L | 足IK.L | 同样全角 |
| 足D.L | 足D | leg_d_L | 下半身 | 准标准骨的变形辅助骨,配合追加变形用 |
| ひざD.L | 膝D | knee_d_L | 足D.L | |
| 足首D.L | 踝D | ankle_d_L | ひざD.L |
注意:
足IK.L里的IK是全角字母,这是 VPVP 标准模型沿用的写法。我自己就踩过这个坑,脚本里写足IK.L(半角)跑了半天,IK 骨死活匹配不上,最后逐字节对比才发现是全角半角的问题。
2.4 辅助骨物理骨与表情相关骨
这一层是最自由、最没有标准的部分,但它在实际效果里占的比重反而最大。模型好不好看,一半靠这些骨。
物理骨主要通过"刚体+关节"驱动,骨骼本身往往被设为"物理后变形"。常见命名有髪(头发)、スカート(裙子)、胸(胸部)、尻(臀部)、リボン(缎带)、マフラー(围巾)。裙子通常按スカート_0_1、スカート_0_2这种"部件_横排_竖排"的方式命名,也见过スカート1_L这种左右分家的写法,没有任何统一规范。
表情与视线相关骨比较固定的是両目、目.L/R、あご(下巴)、舌、涙(眼泪)。あご和舌只在少数高精度模型上出现,做口型同步时用得上。
显示用骨比如グルーブ其实在 MMD 的骨骼显示面板里默认是隐藏的,它纯粹是逻辑上的中间层。类似的还有肩P、腕捩,这些骨在 MMD 界面里手动摆姿势时基本用不到,但物理和动作数据会驱动它们。
我在整理对照表时有个小习惯:给每根骨标注"是否会被 VMD 动作直接驱动"。标准骨和大部分准标准骨会被驱动,物理骨和 D 骨基本只被内部机制驱动。这个标注在你排查"为什么这个动作套上去以后裙子不动"的时候特别省事。
3. 对照表落地使用的三个实战场景
整理出表格只完成了一半,真正的价值在于把它用起来。下面三个场景是我这几年遇到频率最高的,每个场景的处理思路都不太一样。
3.1 场景一:VMD动作在不同命名的模型之间移植
把 A 模型的动作套到 B 模型上,是骨骼对照最经典的使用场景。整个流程里最关键的一点是:VMD 文件是按骨骼名称字符串匹配的,不是按索引。也就是说,哪怕两个模型的骨骼结构和顺序完全一致,只要名字差一个字,动作就套不上。
更麻烦的是 VMD 格式对骨骼名有硬性限制——名称字段长度固定为 15 字节的 Shift-JIS 编码。一个日文假名占 2 字节,所以上半身2占 8 字节没问题,つま先IK.L占 12 字节也没问题,但如果某个模型作者把骨骼名写成左手中指第1关节(9 个汉字 = 18 字节),超出部分会被截断,动作数据就永远匹配不上。
我的处理顺序是这样的:
- 先把目标模型的骨骼列表完整导出,跟动作作者常用骨骼名做个差集。
- 差异项里,凡是"结构相同只是叫法不同"的,直接改名对齐;凡是"结构不同"的,老老实实做映射。
- 改名只在本地名上做,通用名字段保持原样,避免破坏导出到其他引擎的兼容性。
- 改完先套一个包含走位、挥手、转身的测试动作,确认
センター、上半身2、腕捩这几根关键骨都动起来了。
改名的原则是"改模型迁就动作",而不是反过来。原因很现实:一份热门动作数据可能有几万个模型在用,而你的模型只有一个。
3.2 场景二:写脚本批量生成骨骼对照表
手工整理对照表在骨骼数超过一百的时候就彻底不现实了。用脚本读取 PMX 并导出骨骼名,是我目前最推荐的做法。
# 读取 PMX 文件,导出骨骼索引、本地名、通用名 # 依赖 pymeshio:pip install pymeshio import pymeshio.pmx.reader as pmx_reader model = pmx_reader.read_from_file("your_model.pmx") print(f"骨骼总数: {len(model.bones)}") print(f"{'索引':>4} | {'本地名':<16} | {'通用名':<18} | 父骨") print("-" * 60) for idx, bone in enumerate(model.bones): parent = bone.parent_index parent_name = model.bones[parent].name if parent >= 0 else "ROOT" # 用 utf-8 输出到控制台,避免日文乱码 print(f"{idx:>4} | {bone.name:<16} | {bone.english_name:<18} | {parent_name}")跑完这个脚本,你会得到一份完整的骨骼清单。接下来把清单和标准名做个模糊匹配,就能快速找出命名不一致的地方。我常用的匹配策略是分三级:
| 匹配级别 | 判断依据 | 处理方式 |
|---|---|---|
| 完全匹配 | 名称字符串完全一致 | 直接可以用,无需处理 |
| 结构匹配 | 父骨链和位置大致对应 | 建立别名映射,脚本自动替换 |
| 无法匹配 | 结构也对不上 | 人工介入,判断是否要新增骨骼 |
# 别名映射表:把模型里的方言名映射到标准名 # 键是模型里的名字,值是标准动作数据里的名字 ALIAS_MAP = { "肘.L": "ひじ.L", "肘.R": "ひじ.R", "膝.L": "ひざ.L", "膝.R": "ひざ.R", "足IK.L": "足IK.L", # 半角转全角 "足IK.R": "足IK.R", "上半身1": "上半身", "アッパーボディ": "上半身", } def normalize(name: str) -> str: # 先做去空格和统一大小写,再查别名表 key = name.strip() return ALIAS_MAP.get(key, key)这段代码里足IK.L到足IK.L的映射,就是上面提到的全角半角问题。韩国、国内和部分欧美作者做的模型经常写成半角,套标准动作就会丢 IK。
3.3 场景三:外部动捕数据重定向到PMX
用动捕设备或者从别的软件导出 BVH、FBX 数据,再重定向到 PMX 模型上,这个场景对骨骼命名对照的要求最高。因为动捕数据的骨骼命名体系跟 MMD 完全是两套东西,像Hips、Spine、LeftUpperArm到センター、上半身、腕.L,中间要经过一层完整的语义映射。
我的建议是不要直接在 MMD 里操作,先用 Blender 做中转。流程是:导入动捕数据,导入 PMX 模型(用 MMD Tools 插件),然后在 Blender 里做骨骼重定向,最后导出 VMD。
这里有一个必须注意的坐标系问题:MMD 用的是左手坐标系,Y 轴朝上、Z 轴朝前;Blender 是右手坐标系,Z 轴朝上;大多数动捕数据是右手系。三套坐标系叠在一起,如果不做轴变换,重定向完的动作要么上下颠倒,要么左右镜像。我一般在 Blender 里统一处理,让 MMD Tools 负责最后的轴向转换,这样比在 MMD 本体里硬调要可靠得多。
重定向时的映射表建议按"层级优先"来组织,先映射根骨链,再映射四肢,最后映射手指和辅助骨。根骨错了整体位置就全错,先修根骨能避免后面反复返工。
4. 常见坑与排查速查表
这一节是我自己踩过、也看别人踩过的坑的汇总。骨骼名称对照这件事,八成的问题都不在"概念不理解",而在字符和结构层面的细节。
4.1 字符层面的三个隐形杀手
第一个是全角半角。前面已经说过足IK.L的问题,其实不止这一处。有些模型会把点号写成全角.而不是半角.,从视觉上看几乎分辨不出来,但字符串比较直接失败。我的做法是脚本里加一层字符规范化,把所有全角标点统一转成半角再比较。
import unicodedata def normalize_width(s: str) -> str: # 把全角字符统一转成半角,保留假名和汉字 result = [] for ch in s: code = ord(ch) # 全角字母数字和标点区间 if 0xFF01 <= code <= 0xFF5E: result.append(chr(code - 0xFEE0)) else: result.append(ch) return "".join(result)第二个是 VMD 的 15 字节截断。骨骼名超过 15 字节的模型,在 MMD 本体里做动作没问题,但一旦经过某些工具中转,名字会被截断。对策是尽量把本地名控制在 7 个日文字符以内,超出的用缩写。
第三个是编码。VMD 用 Shift-JIS 存名字,PMX 用 UTF-16 或 UTF-8(取决于版本和作者),中间转换一次就可能出现乱码。用脚本处理时,读 PMX 一律按二进制路径读,让解析库负责解码,不要自己open(..., encoding='...')硬读。
4.2 结构层面的三个高频陷阱
IK 骨被当成普通骨处理。足IK.L在 PMX 里是一根带 IK 设置的骨,它的位置在脚尖附近,但旋转它并不会让大腿跟着转——真正让腿动起来的是 IK 求解器驱动的足.L和ひざ.L。如果重定向脚本把 IK 骨当成普通骨直接写旋转数据,腿会原地扭成一团。
D 骨和捩り骨被遗漏。这类骨不参与动作数据的直接驱动,但它们是"追加变形"的接收端。如果模型改造时把腕捩.L删掉了,手臂扭转的效果就没了,表现为前臂在旋转时出现明显的"糖纸收缩"。判断方法很简单:手臂绕自身轴转 90 度,看前臂有没有变细。
根骨映射反了。全ての親和センター都像是根骨,但它们在层级上是父子关系。把动捕数据的Hips映射到全ての親,转身的时候就会变成整个模型绕脚底转,而不是绕重心转。正确做法是把Hips映射到センター,全ての親留给整体的世界位移。
4.3 骨骼匹配问题排查速查表
| 现象 | 最可能的原因 | 排查动作 |
|---|---|---|
| 动作套上后完全不动 | 骨骼名整体不匹配,或 VMD 版本不兼容 | 导出目标模型骨骼列表,逐条比对 |
| 只有某条腿不动 | 该侧足IK全角半角不一致 | 直接肉眼比对字符,或用脚本做宽度规范化 |
| 手臂旋转时变细 | 腕捩或手捩缺失/未映射 | 检查这两根骨是否存在且名称匹配 |
| 裙子飘不起来 | 物理骨名不在动作认可范围内(正常),或刚体关节设置丢失 | 检查物理设置,不要指望动作数据驱动物理骨 |
| 转身时整体绕脚转 | 全ての親与センター映射颠倒 | 检查根骨层级,确认父子关系 |
| 手指僵直 | 手指骨命名与动作数据的编号体系不一致 | 检查親指0是否存在,其余手指是否从 1 开始 |
| 导入后骨骼名显示乱码 | 编码不匹配 | 用二进制方式读取,交给解析库处理 |
| 改名后物理失效 | 破坏了刚体/关节对骨骼的引用 | 改名要用 PMX Editor 的批量替换,不要手工逐条改 |
提示:排查骨骼匹配问题时,最快的办法不是看眼睛比字符串,而是导出两份骨骼名列表丢进 diff 工具。人眼对
ひじ和肘的差异不敏感,对I和I更是完全没有识别能力。
5. 我在实际改名前会走的一套固定流程
前面讲的都是理论和排查,最后说一下我每次动骨骼名之前会走的固定流程。这套流程的核心目的是:任何改名动作都必须可回滚、可验证、可批量。
5.1 改名前必须确认的四件事
第一件,确认模型的本地名和通用名是否分家。如果通用名字段是空的,说明原作者没考虑跨引擎使用,改动空间比较大;如果通用名有内容,那本地名最好别动,改通用名就够用了。
第二件,确认物理设置里的刚体、关节引用的骨是哪些。有些物理设置会直接引用骨骼索引,改名不影响;但如果你是用工具做的重命名,工具可能顺手重建了骨骼列表,索引一变,物理就全乱了。稳妥的做法是用 PMX Editor 的"名称检索替换"功能,它只改字符串不动结构。
第三件,确认模型有没有自定义表情(Morph)里绑定了骨骼。比如有些模型做了笑い表情,实际是驱动口或者あご骨。改名后这些表情可能失效,需要一并检查。
第四件,准备好一份测试动作。我常用的是自己攒的一个小文件,只包含最基础的几帧:抬手、抬腿、转身、下蹲。改完名直接套上去看,十秒钟就能判断有没有大问题,比全流程测一遍快得多。
5.2 一套可以直接抄的批量改名方案
在 Blender 里配合 MMD Tools 做批量改名,比在 PMX Editor 里手点要快得多,尤其是需要改几十根骨的时候。下面这段代码是我用了很久的模板:
import bpy # 键是模型当前的名字,值是目标标准名 RENAME_MAP = { "肘.L": "ひじ.L", "肘.R": "ひじ.R", "膝.L": "ひざ.L", "膝.R": "ひざ.R", "アッパーボディ": "上半身", "ロワーボディ": "下半身", } def rename_bones(armature_name="Armature"): arm = bpy.data.objects.get(armature_name) if arm is None: raise RuntimeError("找不到骨架对象,请确认名称") changed = 0 for bone in arm.data.bones: target = RENAME_MAP.get(bone.name) if target is None: continue old = bone.name bone.name = target changed += 1 print(f"{old} -> {target}") print(f"共修改 {changed} 根骨骼") rename_bones()这段代码有两个地方值得说明。一是必须先切到编辑模式之外执行,骨骼重命名在编辑模式下和物体模式下行为不一致,容易出问题。二是重命名会连带更新所有引用该骨骼的地方(顶点组、约束),但不会自动更新自定义属性里存的字符串,如果你的模型上有脚本驱动的自定义属性,需要单独检查。
改完名之后,我会用 MMD Tools 导出一次 PMX,再重新导入,看骨骼列表是否稳定。这一步主要是验证有没有编码或者长度问题。如果重新导入后骨骼名出现问号或者被截断,说明有字符超出了 PMX 或 VMD 的承载范围,需要换更短的写法。
最后分享一个小技巧:把骨骼名对照表存成 CSV,用脚本管理,而不是硬编码在代码里。原因是模型太多了,每个模型都可能有自己的方言,硬编码的字典会越写越长、越来越乱。用 CSV 管理的话,你可以按模型名分文件,用的时候动态加载,改起来也方便,甚至能直接用表格软件筛选。我自己那份表已经积累了三百多行,全靠 CSV 撑着,换成代码里写死早就没法维护了。