BipedPlus
Ep.18 — Customizing 03: 命名规范 & 团队模板
下载 Markdown 含图片下载如果无法访问 YouTube,可在 Bilibili 搜索 OtakuSolutions 频道观看相关内容。
本文档说明如何将 BipedPlus 命名调整为工作室规范,并保存为可重复使用的 common 模板。
如果无法访问 YouTube,可在 Bilibili 搜索 OtakuSolutions 频道观看相关内容。
1. 为什么需要
当 BipedPlus 默认命名(Skin_*、Ctrl_*、Bip001)与团队规则不匹配时,工作流程就会受阻。
可以进行重命名——关键是将结果保存为模板,避免每次重复操作。
2. 完整流程

3. 命名变更的允许范围和注意事项
| 类型 | 内容 |
|---|---|
| ✅ 可以更改 | Biped 名称、Skin 骨骼名称(与引擎骨骼名对应)、控制器前缀、层显示名称 |
| ⚠️ 注意 | 使用统一批量规则重命名,避免破坏 Hierarchy / Constraint / Space |
| ❌ 禁止省略 Fix Missing | 重命名后不执行 Fix Missing 将导致 Mirror / Picker / Reset 失效 |
4. Fix Missing — 重命名后保持系统同步
名称更改后,INFO 记录的旧名称会不匹配,导致 Missing 错误。
| 概念 | 说明 |
|---|---|
| Seed | 即使节点被重命名,也能识别该节点的唯一地址值 |
| Fix Missing | 利用 Seed 重新链接重命名后节点的功能 |
操作步骤:Rig Info → Load → 检查 Missing → 执行 Fix Missing → 确认镜像更新 → 通过 Ani Utils 验证
5. 自定义层名称
层设置 → Edit Name → 新建预设(团队/产品名)→ 添加前缀/后缀 → Apply to Rename
保持 Hierarchy 中的角色分类不变——只将显示标签改为符合团队规范的名称。
6. 保存为 common 模板
| 步骤 | 内容 |
|---|---|
| 1 | 打开建模场景(或新建文件) |
| 2 | Merge — common/BP_Human_Template.max 中的所有节点 |
| 3 | BipedPlus Scan — 确认 INFO / 镜像等已保留 |
| 4 | 按角色调整 Figure / 比例等 |
| 5 | 保存到角色文件夹 → 分发给动画团队(使用 Player 工作) |
共享_绑定/
├── character_A/
├── character_B/
└── common/
└── BP_Human_Template.max ← 已配置命名、层级和 INFO 的主模板
7. Picker 的例外
| INFO / Ani Utils(Fix Missing 后) | Picker | |
|---|---|---|
| 重命名后 | 可恢复 | 基于名称——布局可能失效 |
推荐:在命名和模板确定后,用新命名重建 Picker,并与模板 .max 一起分发给团队。
Picker 文件位置在 BipedPlus Settings 中查看。
8. 检查清单
- [ ] 团队的 bone / Ctrl / Layer 命名规则已文档化
- [ ] 使用批量重命名脚本(或团队脚本)
- [ ] 重命名后:验证 Fix Missing + Mirror / Reset
- [ ]
common/模板.max存在于共享文件夹中 - [ ] 新角色使用 Merge → Scan 工作流程
- [ ] Picker 已按最终命名规范重建
- [ ] 动画团队使用 Player 和相同的安装程序
Example Rename Script (handle 2-pass)
Edit NODE_RENAME_MAP to match your team's rules. Run in Max Script Editor after Build.
# -*- coding: utf-8 -*-
"""BipedPlus naming example (handle 2-pass, short version)"""
import pymxs
rt = pymxs.runtime
NODE_RENAME_MAP = [
("Bip001", "Bip009"),
("Bip001 Pelvis", "Bip009 Pelvis"),
("Ctrl_Head", "CTL_Head"),
("Skin_Spine1", "Bip001_Spine1"),
("Skin_L_Hand", "Bip001_L_Hand"),
]
def rename_nodes_by_handle(rename_map=None):
mapping = rename_map if rename_map is not None else NODE_RENAME_MAP
if not mapping:
raise ValueError("NODE_RENAME_MAP is empty.")
# Phase 1 — collect handles
collected = []
for src, dst in mapping:
node = rt.getNodeByName(src)
if node is None:
print(f"[SKIP] {src}")
continue
collected.append((int(node.handle), src, dst))
if not collected:
raise ValueError("No rename targets found in scene.")
# Phase 2 — apply
for handle, src, dst in collected:
node = rt.maxOps.getNodeByHandle(handle)
if node is None:
raise RuntimeError(f"handle={handle} restore failed ({src} → {dst})")
node.name = dst
print(f"[OK] {src} → {dst}")
print(f"Done ({len(collected)} ok). Next: Rig Info → Fix Missing")
if __name__ == "__main__":
rename_nodes_by_handle()
After running: Rig Info → Fix Missing → verify Mirror / Reset.