name: vrchat-toggle-parameter-linkage description: Complete guide for adding new Toggle-based clothing controls to VRChat avatars — ensuring the full linkage chain from Menu Toggle → VRCExpressionParameters → FX Controller conditions → AnimationClip is correctly wired tags: [vrchat, toggle, parameter, expression-menu, fx-controller, unity, mcp]
VRChat Toggle 参数链路完全指南
⚠️ 此技能必须在每次新增Toggle功能前加载并逐项检查——发现新坑立即更新
使用规则
- 加载此技能后先读完,对照检查清单逐项确认
- 每完成一步操作后,必须对照检查清单打勾
- 发现新的坑/教训立即更新此技能
- 切勿跳过检查直接操作——宁可慢,不可错
核心教训
Toggle 控件的
parameter.name必须设置,否则是空壳按钮
创建一个 VRCExpressionsMenu 的 Toggle 控件时,只设 type = Toggle (102) 是不够的。
必须同时设置 parameter.name,否则点击开关不会改变任何参数值。
⚠️ Toggle value=0 永远无法切换
Toggle 的逻辑:当前值 == control.value 时视为 ON,点击后切换为 OFF(写 0)。
如果 control.value = 0:初始值 0 → 已为 ON → 点击 OFF → 写 0 → 值仍为 0 → 又显示 ON → 循环。
Toggle 的 control.value 不能设为 0。 如果需要参数值为 0 的状态,用 value=1 的 Toggle 并通过 Animator 做映射。
⚠️ Button 是脉冲触发,不是状态保持
Button (type=101):按下设值,松手立即恢复 0。仅适合触发一次性动画。 不能用于 4S 状态循环换装系统 — 参数值不保持,动画播到一半就中断。 Toggle (type=102):ON 时保持 value,OFF 时保持 0。适用于需要状态保持的场景。
⚠️ SubMenu parameter.name 退出时恢复 0(隐藏行为)
SubMenu 的 parameter.name 行为:
- 进入子菜单 → Animator.SetFloat(paramName, control.value)
- 退出子菜单 → Animator.SetFloat(paramName, 0f) ← 这是最常见的陷阱!
- 如果 SubMenu 绑定了与子菜单内 Toggle 相同的参数,退出时会覆盖用户选择。
换装子菜单的 SubMenu 绝对不能绑主 Int 参数。 如果设置了,退出时所有 Toggle 的选择都被恢复为 0。 绑定了与子菜单内 Toggle 相同的参数,退出时会覆盖用户选择。
换装子菜单的 SubMenu 绝对不能绑主 Int 参数。 如果设置了,退出时所有 Toggle 的选择都被恢复为 0。## 完整链路(5层)
新加一个服装 Toggle(如 Shorts)需要在以下 5 个地方全部关联:
1. AnimationClip (ON/OFF)
└── 控制目标 GameObject 的 m_IsActive = 1/0
2. FX Controller BlendTree
└── Inner BlendTree: Shorts_ON (Float) → 0→OFF.anim, 1→ON.anim
└── 作为子节点加入 Layer 14 主 BlendTree
3. FX Controller 参数
└── AddParameter("Shorts_ON", AnimatorControllerParameterType.Float)
4. VRCExpressionParameters
└── parameter.name = "Shorts_ON"
└── valueType = Bool, saved = true, default = 1
5. VRCExpressionsMenu.Toggle
└── control.parameter.name = "Shorts_ON" ← ★最容易被漏掉!
Toggle 控件的正确创建方式
C# (via execute_code / Editor Script)
using VRC.SDK3.Avatars.ScriptableObjects;
VRCExpressionsMenu.Control toggle = new VRCExpressionsMenu.Control();
toggle.name = "内裤"; // 显示文本
toggle.type = (VRCExpressionsMenu.Control.ControlType)102; // Toggle
// ★★★ 必须设置 parameter.name ★★★
toggle.parameter = new VRCExpressionsMenu.Control.Parameter();
toggle.parameter.name = "Shorts_ON"; // 对应参数名
// 添加到菜单
menu.controls[7] = toggle; // 或 Add to list
Unity Editor Inspector
- 选中菜单资产(如
UnderWear_Option.asset) - 在 Inspector 中找到对应的 Toggle 控件
- 在 Parameter 字段输入参数名(如
Shorts_ON) - 点击 Apply
常见错误
❌ 错误1:Toggle 没绑参数
根因:control.parameter.name 未设置,或者 control.parameter = null
✅
但参数不变化 ❌
FX 条件不触发 ❌
动画不执行 ❌
**根因**:`control.parameter.name` 未设置,或者 `control.parameter = null`### ❌ 错误2:参数名拼写不一致
- Menu Toggle: `"Short_ON"`
- VRCExpressionParameters: `"Shorts_ON"`
- FX Controller: `"Shorts_ON"`
→ 大小写和拼写必须完全一致
### ❌ 错误3:在原版文件上直接修改
→ 应该先复制 → 改副本 → VRCAvatarDescriptor 引用副本
## 操作流程(新加服装 Toggle)
### 第1步:创建 AnimationClip
路径:`Assets/Cazalis/Animation/FX/xxx_ON.anim` 和 `xxx_OFF.anim`
- ON clip: 设目标 GameObject 的 `m_IsActive = 1`
- OFF clip: 设目标 GameObject 的 `m_IsActive = 0`
### 第2步:FX Controller — 添加 Inner BlendTree
在 Layer 14 (Cloth_Option) 主 BlendTree 中添加子节点:
1. 复制一个已有的 Inner BlendTree(如 Socks_ON)的结构
2. 修改 `blendParameter` 为新的参数名
3. 把子项指向新创建的 ON/OFF AnimationClip
4. 添加到主 BlendTree 的 children 数组
**关键陷阱**:Inner BlendTree 必须用 `AssetDatabase.AddObjectToAsset(bt, controller)` 序列化,否则不持久化
### 第3步:FX Controller — 添加参数
```csharp
ctrl.AddParameter("Shorts_ON", UnityEngine.AnimatorControllerParameterType.Float);
第4步:VRCExpressionParameters — 添加参数
通过 manage_asset.modify 或者 C# 代码修改(推荐用副本):
var newParams = new VRCExpressionParameters.Parameter[oldParams.Length + 1];
Array.Copy(oldParams, newParams, oldParams.Length);
newParams[oldParams.Length] = new VRCExpressionParameters.Parameter {
name = "Shorts_ON",
valueType = VRCExpressionParameters.ValueType.Bool,
saved = true,
networkSynced = true,
defaultValue = 1f // 默认显示
};
paramAsset.parameters = newParams;
第5步:菜单 — 添加 Toggle
- 创建或复用子菜单资产
- 添加 Control,type=Toggle,parameter.name=参数名
-
在根菜单中添加 SubMenu 入口指向子菜单 单 — 添加 Toggle
-
创建或复用子菜单资产
- 添加 Control,type=Toggle,parameter.name=参数名
- 在根菜单中添加 SubMenu 入口指向子菜单### 第6步:VRCAvatarDescriptor 引用(只改一次)
改好所有副本后,在 VRCAvatarDescriptor 上一处全改:
expressionsMenu→Cazalis_Menu_ModifiedexpressionParameters→Cazalis_Parameter_Modified- FX Layer →
Cazalis_FX_Modified.controller
验证清单(上传测试前)
- 各资产使用的是副本,不是原版
- Toggle Control 的
parameter.name已设置 - 参数名在 Menu / VRCExpressionParameters / FX Controller 三处完全一致
- VRCExpressionParameters 的
saved=true(参数保存到服务器) - VRCExpressionParameters 的
defaultValue与 GameObject 默认 active 状态一致 - FX Controller 的 Animator 参数已添加(类型 Float,与 VRCExpressionParameters 的 Bool 兼容)
- Inner BlendTree 已通过
AddObjectToAsset序列化 - VRCAvatarDescriptor 引用了所有副本
- ON/OFF AnimationClip 的绑定路径正确
相关资产
UnderWear_Option.asset— 内衣子菜单(含 Bra/Shorts Toggle)Cazalis_Parameter_Modified.asset— 参数文件副本(含 Shorts_ON)Cazalis_FX_Modified.controller— FX 控制器副本Cazalis_Menu_Modified.asset— 根菜单副本Cloth_Option_SubMenu_Modified.asset— 服装子菜单副本 — FX 控制器副本Cazalis_Menu_Modified.asset— 根菜单副本Cloth_Option_SubMenu_Modified.asset— 服装子菜单副本## Unity 中文英文对照(用于给小白用户指引)
| 英文 | 中文 | 用途 |
|---|---|---|
| Window | 窗口 | 顶部菜单栏 |
| Animation | 动画 | 分类 |
| Animator | 动画器 | 状态机编辑器(Ctrl+6) |
| Layer | 层 | Animator 左下角面板 |
| BlendShapes | 混合变形 | SkinnedMeshRenderer 底部 |
| Skinned Mesh Renderer | 蒙皮网格渲染器 | 模型渲染组件 |
| Inspector | 检视面板 | 右侧属性面板 |
| Hierarchy | 层级 | 左侧对象列表 |
| Clamp BlendShapes | 钳制混合变形 | 限制 0-100,齿轮图标取消勾选 |
| Transition | 过渡/转换 | 状态之间的箭头连线 |
| State | 状态 | 状态机的方块 |
| AnimatorController | 动画器控制器 | .controller 文件 |
| AnimationClip | 动画剪辑 | .anim 文件 |
| BlendTree | 混合树 | 1D/2D/Direct 混合 |