title: Expression Menu 配置 description: V3版 — VRChat 菜单系统配置,参数示例对齐 taozhuang created: 2026-05-09 updated: 2026-05-27 type: reference tags: [vrchat, avatar, expression-menu, parameters, vrcsdk, v3, taozhuang]
Expression Menu 配置
[!NOTE] 本文档为 V3 版本,菜单示例中的服装参数已更新为
taozhuang(Int, 0-3)。 V3 服装切换使用 Button 控件直接赋值taozhuang值,而非 Toggle。
核心组件
1. VRCExpressionsMenu
路径:在 Project 中创建的 ScriptableObject
位置:通常在 Assets/.../EXMenu/ 下
例子:
- Assets/Cazalis/Animation/EXMenu/Cazalis_Menu.asset
2. VRCExpressionParameters
路径:Assets/.../EXMenu/Cazalis_Parameter.asset
用途:定义所有 VRC 参数(Bool/Int/Float)
3. VRCAvatarDescriptor
属性:
- expressionsMenu — 关联的菜单资产
- expressionParameters — 关联的参数资产
- customExpressions — 是否启用自定义表达式
控制类型 (ControlType)
| 值 | 类型 | 说明 | 对应参数 |
|---|---|---|---|
101 |
Button | 按钮,按下触发一次 | Int/Float |
102 |
Toggle | 开关,true/false 切换 | Bool |
103 |
SubMenu | 子菜单,进入二级菜单 | 无参数 |
201 |
TwoAxisPuppet | 二轴控制器 | Float x2 |
202 |
FourAxisPuppet | 四轴控制器 | Float x4 |
203 |
RadialPuppet | 径向控制器 | Float x1 |
菜单结构设计
| 202 | FourAxisPuppet | 四轴控制器 | Float x4 |
| 203 | RadialPuppet | 径向控制器 | Float x1 |
菜单结构设计### V3 目标菜单
根菜单 (Cazalis_Menu)
├── 蝴蝶结 (Toggle) → Butterfly_ON
├── 服装 (SubMenu)
│ ├── 原皮 (Button) → taozhuang = 0
│ ├── 露肩短裙 (Button) → taozhuang = 1
│ ├── 休闲服 (Button) → taozhuang = 2
│ ├── 开衫毛衣 (Button) → taozhuang = 3
│ └── Blanchir (Button) → taozhuang = 5
├── 发型 (SubMenu)
│ ├── 短发 (Toggle) → Hair = 0
│ └── 长发 (Toggle) → Hair = 1
└── 缩放 (SubMenu)
├── 胸部大小 (Radial) → Breasts_Size
└── 腿粗细 (Radial) → Futomomo_Size
[!NOTE] V3 服装切换使用 Button 控件(类型
101),而非 Toggle,直接赋值taozhuang参数(Int 0-5,其中4对应娃花)。 如需内衣穿透等 Bool 开关,仍使用 Toggle 控件。
添加菜单项(C# 代码)
添加服装 Button(V3 taozhuang)
using VRC.SDK3.Avatars.ScriptableObjects;
VRCExpressionsMenu menu = AssetDatabase.LoadAssetAtPath<VRCExpressionsMenu>(
"Assets/Cazalis/Animation/EXMenu/Cazalis_Menu.asset"
);
VRCExpressionsMenu.Control button = new VRCExpressionsMenu.Control();
button.name = "露肩短裙";
button.type = (VRCExpressionsMenu.Control.ControlType)101; // Button
button.parameter = new VRCExpressionsMenu.Control.Parameter();
button.parameter.name = "taozhuang";
List<VRCExpressionsMenu.Control> controls = menu.controls.ToList();
controls.Add(button);
menu.controls = controls.ToArray();
EditorUtility.SetDirty(menu);
AssetDatabase.SaveAssets();
EditorUtility.SetDirty(menu); AssetDatabase.SaveAssets(); ```### 添加 Bool Toggle
using VRC.SDK3.Avatars.ScriptableObjects;
VRCExpressionsMenu.Control toggle = new VRCExpressionsMenu.Control();
toggle.name = "内衣";
toggle.type = (VRCExpressionsMenu.Control.ControlType)102; // Toggle
toggle.parameter = new VRCExpressionsMenu.Control.Parameter();
toggle.parameter.name = "Bra"; // 对应 Animator Bool 参数
List<VRCExpressionsMenu.Control> controls = menu.controls.ToList();
controls.Add(toggle);
menu.controls = controls.ToArray();
EditorUtility.SetDirty(menu);
AssetDatabase.SaveAssets();
参数配置
VRCExpressionParameters
VRCExpressionParameters parameters = AssetDatabase.LoadAssetAtPath<VRCExpressionParameters>(
"Assets/Cazalis/Animation/EXMenu/Cazalis_Parameter.asset"
);
// V3 taozhuang 参数定义
VRCExpressionParameters.Parameter taozhuangParam = new VRCExpressionParameters.Parameter
{
name = "taozhuang",
valueType = VRCExpressionParameters.ValueType.Int,
defaultValue = 0f,
saved = true,
networkSynced = true
};
// 例如在参数数组中添加
parameters.parameters[0] = taozhuangParam;
EditorUtility.SetDirty(parameters);
AssetDatabase.SaveAssets();
参数属性
| 属性 | 说明 |
|---|---|
name |
参数名(与 Animator 参数对应) |
valueType |
Bool / Int / Float |
defaultValue |
默认值 |
saved |
是否保存到服务器 |
networkSynced |
是否网络同步 |
SubMenu 配置
Float |
| defaultValue | 默认值 |
| saved | 是否保存到服务器 |
| networkSynced | 是否网络同步 |
SubMenu 配置### 子菜单结构
VRCExpressionsMenu subMenu = new VRCExpressionsMenu();
// V3 服装子菜单
subMenu.controls = new VRCExpressionsMenu.Control[]
{
new VRCExpressionsMenu.Control {
name = "原皮",
type = (VRCExpressionsMenu.Control.ControlType)101, // Button
parameter = new VRCExpressionsMenu.Control.Parameter { name = "taozhuang" },
value = 0f
},
new VRCExpressionsMenu.Control {
name = "露肩短裙",
type = (VRCExpressionsMenu.Control.ControlType)101, // Button
parameter = new VRCExpressionsMenu.Control.Parameter { name = "taozhuang" },
value = 1f
},
new VRCExpressionsMenu.Control {
name = "休闲服",
type = (VRCExpressionsMenu.Control.ControlType)101, // Button
parameter = new VRCExpressionsMenu.Control.Parameter { name = "taozhuang" },
value = 2f
},
new VRCExpressionsMenu.Control {
name = "开衫毛衣",
type = (VRCExpressionsMenu.Control.ControlType)101, // Button
parameter = new VRCExpressionsMenu.Control.Parameter { name = "taozhuang" },
value = 3f
},
new VRCExpressionsMenu.Control {
name = "Blanchir",
type = (VRCExpressionsMenu.Control.ControlType)101, // Button
parameter = new VRCExpressionsMenu.Control.Parameter { name = "taozhuang" },
value = 5f
}
};
AssetDatabase.CreateAsset(subMenu, "Assets/MySubMenu.asset");
已知问题
value = 5f
}
};
AssetDatabase.CreateAsset(subMenu, "Assets/MySubMenu.asset");
## 已知问题### 参数引用未设置
添加 Toggle 控制项后,`parameter` 属性可能为 null:
```csharp
// 错误:parameter 未设置
control.parameter = null; // ❌
// 正确:引用正确的参数对象
VRCExpressionParameters.Parameter targetParam = Array.Find(parameters.parameters,
p => p.name == "Bra");
control.parameter = targetParam; // ✅
命名大小写
Animator 参数名区分大小写:
- Bra ≠ bra ≠ BRA
绑定到 Avatar
在 VRCAvatarDescriptor 中
VRCAvatarDescriptor descriptor = avatar.GetComponent<VRCAvatarDescriptor>();
// 启用自定义表达式
descriptor.customExpressions = true;
// 关联菜单
descriptor.expressionsMenu = menuAsset;
// 关联参数
descriptor.expressionParameters = parametersAsset;