跳转至

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功能前加载并逐项检查——发现新坑立即更新

使用规则

  1. 加载此技能后先读完,对照检查清单逐项确认
  2. 每完成一步操作后,必须对照检查清单打勾
  3. 发现新的坑/教训立即更新此技能
  4. 切勿跳过检查直接操作——宁可慢,不可错

核心教训

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

  1. 选中菜单资产(如 UnderWear_Option.asset
  2. 在 Inspector 中找到对应的 Toggle 控件
  3. Parameter 字段输入参数名(如 Shorts_ON
  4. 点击 Apply

常见错误

❌ 错误1:Toggle 没绑参数

菜单显示 Bra/Shorts 开关 ✅
点击有反馈 ✅
但参数不变化 ❌
FX 条件不触发 ❌
动画不执行 ❌

根因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

  1. 创建或复用子菜单资产
  2. 添加 Control,type=Toggle,parameter.name=参数名
  3. 在根菜单中添加 SubMenu 入口指向子菜单 单 — 添加 Toggle

  4. 创建或复用子菜单资产

  5. 添加 Control,type=Toggle,parameter.name=参数名
  6. 在根菜单中添加 SubMenu 入口指向子菜单### 第6步:VRCAvatarDescriptor 引用(只改一次)

改好所有副本后,在 VRCAvatarDescriptor 上一处全改:

  • expressionsMenuCazalis_Menu_Modified
  • expressionParametersCazalis_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 混合