关于 scenario-unity-animation
scenario-unity-animation 面向使用 Unity 的 Agent,指导其通过数据构建和验证动画系统,无需依赖 Animator、Timeline 或 Scene 窗口。内容涵盖导入、控制器、绑定、摄像机、根运动和过场,并以可测量的检查验证结果。
主要功能
- 01自动化动画导入规则
- 02Animator 控制器与混合树
- 03确定性动画采样
- 04绑定与摄像机设置
- 05Timeline 过场验证
适用场景
- 01导入并审查角色动画片段
- 02检查移动速度和脚部滑动
- 03构建瞄准绑定并验证约束
- 04测试摄像机混合与过场交接
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-unity-animation安装后在 Claude Code 中输入/scenario-unity-animation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/ut_animation.pyscripts/AgentKit/Animation/AnimCinemachine.csAnimControllerBuilder.csAnimImport.csAnimPackages.csAnimPlayMode.csAnimProcedural.csAnimRigging.csAnimSampler.csAnimTimeline.csAnimUtil.csscripts/Runtime/AgentAnimationGraph.csAgentLightClip.csAgentLightTrack.csAgentMarker.csAgentMarkerReceiver.csAgentRootMotionMover.csSecondOrderDynamics.cs详细介绍
Unity 动画(Animator 和 Technical Animator)
在 Unity 中进行专业级动画工作,关键在于顺序和测量:由列表顺序决定哪个图层、约束、过渡或摄像机生效;则通过从动画片段中获取的数值来判断脚步、瞄准和混合是否正确。没有 Animator、Timeline 或 Scene 窗口的 Agent,会根据数据构建所有内容(AnimatorController、TimelineAsset、Cinemachine 和 Rigging 组件),以确定性方式逐步运行、测量并查看接触表。目标版本:Unity 6000.3.21f1、Cinemachine 3.1.7、Animation Rigging 1.4.1、Timeline 1.8.12。如果这里提到的同级技能不在可用技能中,请让用户安装该技能(npx skills add scenario-labs/skills --skill <name>);若无人在场,则根据工具架构继续操作,并标明这一缺口。
必备背景: scenario-unity-expert(通道、审查循环、6.3 中的陷阱)。工具包:scripts/ut_animation.py 和 scripts/AgentKit/Animation/ 中的 C# 作业(命名空间 AgentKit.Animation),以及 scripts/Runtime/ 中的运行时代码。使用 ut_animation.install(P) 安装。
立场(专业经验增量)
- 顺序决定行为,无处不在。 Animator 层级越低,优先级越高(iHeartGameDev,W0eRZGS6dhQ [00:05:04]);Additive 会在遇到第一个 Override 时停止 [00:09:46];默认情况下,过渡不可中断;启用 Ordered Interruption 后,只有排在当前运行过渡之前的过渡才能插入,顺序相同则按列表顺序处理(Catherine Proulx,Unity 博客;实测:她的 None、有序、无序和同帧情况均可复现)。中断时会从冻结的姿势快照开始混合(实测:中断帧骨骼运动速度为 0 度/秒):应让用于中断的过渡保持较短 [推论]。骨架约束按深度优先顺序求解,先脊柱,再头部或手部(Code Monkey,luBBz5oeR4Q [00:06:20];实测头部误差为 0.0 度,而非 17.9 度)。
- 混合树坐标使用游戏内单位。 子项使用实测的
averageSpeed/averageAngularSpeed,而不是 0 / 0.5 / 1(_J8RPIaO2Lc [00:16:30]);将运行时参数限制在子项的范围内,否则速度持续上升时,边缘姿势会保持不变 [帧 00:13:38]。脚本速度与动画片段不一致会导致脚底滑动(Ketra Games,mNxEetKzc04 [00:00:32];实测滑动速度 p50 为 0.19,而非 1.14 米/秒)。 - 当待机姿势与行走姿势不同时,待机应作为独立状态(IsMoving 上不设置退出时间),混合树从慢速行走开始(mNxEetKzc04 [00:08:54])。只有在脚本速度驱动原地动画片段时,才适合将待机放在混合树原点(_J8RPIaO2Lc [00:04:24])。
- 根运动按动画片段和轴分别决定(6.3 手册):待机动画烘焙旋转、Y 轴和 XZ 轴;直线移动动画烘焙旋转和 Y 轴;转向动画保留旋转;改变高度的动画不烘焙 Y 轴,并使用 Based Upon Feet,这样混合时不会漂浮,脚本控制的跳跃也不会重复叠加动画片段中的髋部上升。**Based Upon 从不会导致漂移:**烘焙的轴无论该设置为何值,位移都为零;它只决定姿势的位置。Original 保留文件中的朝向和位置(Ketra 以这种方式烘焙 Mixamo 待机动画,不会漂移);Body Orientation 会重新居中动作捕捉片段(实测 30 秒内:两者漂移均为 0 米,但 Original 的朝向偏差 88 度,位置偏移 2.43 米;XZ 未烘焙时漂移 0.246 米)。在
OnAnimatorMove中只调用一次CharacterController.Move(deltaPosition + y),绝不要使用deltaPosition * Time.deltaTime[00:07:21]。Y 轴已烘焙的动画片段中,Animator.gravityWeight为 1;Y 轴未烘焙的动画片段中为 0,并在过渡期间混合(手册;实测如此,关闭根运动时则始终为 0)。 - 从一个参考文件自动化导入,并限定作用文件夹(git-amend,V9_Z6hUOG_8):在
OnPreprocessModel中设置骨架,在OnPreprocessAnimation中设置动画片段;规则变更时递增GetVersion();绝不要在回调中重新导入。角色类型应根据文件名或规则确定,绝不要取动画片段名称:每个 Mixamo 动作名称都是“mixamo.com”。引用 FBX 子资源中的动画片段;在切换到 Humanoid 前复制的动画片段会保留骨骼路径(BEZHVYk6Fa4 [00:12:03];实测:它使 humanoid 移动了 0.0 度,而切换后复制的版本移动了 40.1 度)。从不同层级结构中 Copy From Other 会导入 0 个动画片段,且仅在导入日志中报告(已观察到)。默认关闭 Translation DoF [00:02:21]。 - 蒙皮掩码创建层,参考姿势创建 Additive 层。 没有蒙皮掩码的 Override 层会替换整个身体;Additive 动画片段只有在其创作时的基础姿势之上才有效(W0eRZGS6dhQ [00:05:33],[00:09:57])。导入时使用蒙皮掩码,去除动画片段不需要的手指和 IK 目标(手册,成本)。
- 摄像机:只用一个 Brain,移动目标,并根据游戏类型选择 Rig(Unity CM3.1 系列)。Smart Update 加 Late Update 在出现抖动时优先进行混合(Brain 文档)。肩后视角使用 Third Person Follow;FreeLook、Camera Offset 和 Deoccluder 会相互冲突(u0a1F6BlczE [00:02:41])。程序化 Position Control 会覆盖动画;绝不要将其设为移动物体的子级(XTVzs4B1d7I [00:03:10])。位于目标相对两侧的摄像机会穿过目标进行混合:使用 CylindricalPosition 提示(实测:不设置时为 0.5 米,朝向点积为 0.0;Cylindrical 时为 5.02 米,朝向点积为 0.995;仅设置 IgnoreTarget 时仍为 0.5 米)[00:13:32]。Deoccluder:将玩家设为 Ignore Tag,将玻璃设为 Transparent Layers;触发器永远不计入(实测)。Timeline 会覆盖 Brain:在其停止前,优先级设置会被忽略(Play 模式下实测)。
- Timeline:持续动作使用轨道,瞬时事件使用标记,没有负载时使用 Signals(Ciro Continisio,gsEe0_o_934 [00:18:53])。接收器会收到路由给它的每一条通知:应检查类型 [帧 00:22:57]。拖动时间轴时混合器也会运行;在
OnGraphStart中生成对象,并在之后销毁 [00:45:30]。
首先确定
平台和帧预算(性能交接数据);3D 骨骼动画还是 2D 精灵(精灵请转至 scenario-unity-2d);绑定类型(用于重定向和 Mixamo 时选 Humanoid;只有一个骨架且注重 成本时选 Generic;Generic 根运动通过 Root Node 生效);根运动(玩家脚部质量)还是 原地动画(NavMesh AI、精确控制速度);内容来源:Mixamo(用于 Unity 的 FBX,30 fps,关键帧 简化为 none,使用同一个 Mixamo 角色,动画片段选 Without Skin;根运动:In Place 关闭, Character Arm Space 调高;mNxEetKzc04 [00:03:04]、_J8RPIaO2Lc [00:01:24])、要拆分的 动作捕捉录制、DCC;摄像机风格;项目中是否已有 CM2?;过场动画时长和分支。默认值: Humanoid、玩家使用根运动、CM 3.1.7、30 fps Timeline、Input System。
工作流
- 包。 使用
AnimPackages.Add和["[email protected]", "[email protected]"](异步,quit=False), 然后执行ua.install(P)。GATE:ua.pinned_packages(P)全部通过。 - 导入。
ua.default_rules("Hero.fbx", files)->AnimImport.ImportDrop(规则 JSON、 角色优先、蒙版、修复层级不匹配)。使用AnimSampler.ClipProfile拆分动作。GATE:审计counts.error == 0,Avatar 有效且为 human,每个动画片段均为human_motion,没有anim.role_fallback,文件夹外的 FBX 仍为 Generic;AnimImport.AuditClips没有anim.generic_duplicate。 - 控制器。 Spec ->
AnimControllerBuilder.Build(蒙版、层、auto树位置、 带中断设置的过渡、哈希类)。GATE:counts.error == 0;位置与测得的速度一致;ua.blend_tree_checks(tree, param_ranges)通过;在SampleStates中使用类似ua.interruption_probe_spec的事件证明紧急退出有效。 - 采样和外观。
AnimSampler.SampleStates(Rebind、固定Animator.Update;events、trace、每个样本的clip/controller)、LocomotionMetrics(单独检查一个动画片段时用clip)。GATE:状态符合预期;蒙版骨骼为 0.000 deg;地面速度在 5 % 以内;滑步 p50 < 0.25 m/s; idle 30 s 漂移 < 1 cm;未烘焙 Y 轴的动画片段(启用根运动)中 gravityWeight 为 0;已打开表格。 - 绑定。 先执行
AnimRigging.BuildAimRig,再执行AuditRigs。GATE:头部 < 1 deg,手部 < 1 cm,没有rig.solve_order,已查看帧;移动一个目标,绝不重新绑定(rig.runtime_rebind); 目标移至遮挡物后方时,绑定权重逐渐淡出(Htl7ysv10Qs [00:07:54],Play 模式下采样Rig.weight)。 - 摄像机。
AnimCinemachine.SetupCameras(rigs、blend_hint、deoccluder)、AuditCameras、CameraProbe(Manual Update;obstacles、遮挡 linecast、series)。GATE:每个事件都有实时摄像机;ua.camera_probe_checks为空(无翻转、无穿越摆动、无被遮挡或位于几何体内部的帧);ua.jitter_metrics反转 < 5 % [added];审计 0 warn。 - Timeline。
AnimTimeline.BuildCutscene、SampleCutscene(拖动、帧)、PlayCutscene(Play 模式:标记、信号、实时摄像机、交还控制权)、AuditTimeline。GATE:绑定正确; 混合数值正确;没有根节点跳变;标记和信号各触发一次;审计 0 warn;结束后 Brain 的优先级摄像机处于实时状态。 - 验证和代码。
AnimProcedural.RootMotionPlay(每帧一次 Move),ua.scan_csharp(Assets)通过,将数据交给 scenario-unity-performance。
完整代码和记录结果见流程说明:
references/procedures.md。
数值
| 数值 | 相对于 | 来源 |
|---|---|---|
| Clamp(0.1 x length, 0.1 s, 0.5 x length) | 单次混合;在 length 减去 blend 处淡出 | fQzKJO-0dS8 [00:07:58] |
| 0.7 aim / 0.3 look | 手部瞄准时的胸部权重 / 头部注视 | luBBz5oeR4Q [00:06:53]; Htl7ysv10Qs [00:08:59] |
| -100..100 deg | 头部瞄准限制,后方淡出权重 | Htl7ysv10Qs [00:06:58] |
| Min 1 s, Wait 0 | 针对闪烁状态的 State-Driven 摄像机 | u0a1F6BlczE [00:09:32] |
| primary 2, fallback 1 | ClearShot 优先级 | u0a1F6BlczE [00:14:53] |
| 30 fps, keyframe reduction none | Mixamo 下载 | _J8RPIaO2Lc [00:01:24] |
| T < sqrt(4 k2 + k1^2) - k1 | 二阶稳定性 | KPoeNZZ6H4s [00:12:29] |
| 1.08 / 3.51 m/s, -98 / +77 deg/s | Unity 示例动作捕捉中的行走、慢跑和转身 | 观测 |
| 0 m vs 0.246 m | 30 s 静止漂移,XZ 已烘焙 vs 未烘焙 | 观测 |
| 0.5 m vs 5.02 m | 摄像机最近距离,无提示 vs 圆柱形 | 观测 |
质量门槛
- **可测量:**导入审计和 AuditClips 无问题;控制器审计;遮罩检查;速度误差在 5 % 以内; 滑动 p50;静止漂移;绑定错误;摄像机探测检查和抖动;Timeline 绑定、事件、 审计;每帧一个 Move;C# 扫描。
- **视觉:**每个阶段都要根据
references/critique.md评审联系表(T 字姿势、脚陷入地面、手臂穿过 身体、突变、摄像机翻转、取景);ut_review无标记。
常见错误
| 错误 | 表现 | 修正 |
|---|---|---|
| 采样时的 Culling Mode 不是 Always Animate | 批量捕获显示绑定姿势 | 采样器会强制使用 Always Animate(已观察到) |
| 根据 Take 名称选择标志 | 每个 Mixamo 动画片段都使用相同的循环和烘焙标志 | 根据文件名或规则指定角色;重命名动画片段 |
| 未限定范围的导入处理器 | 项目中的每个 FBX 都变成 Humanoid | 使用规则文件或 assetPath 守卫;ua.scan_csharp |
| 根 Y 已烘焙的跳跃动画片段 | 混合时漂浮;髋部抬升叠加到脚本控制的跳跃上 | 不烘焙 Y,Based Upon 设为 Feet |
切换到 Humanoid 前复制 .anim | 动画片段无法在 humanoid 上播放 | 切换后重新复制,或引用 FBX 动画片段 |
| 在不同层级结构上使用 Copy From Other | FBX 导入后没有动画片段,控制台也没有提示 | 查看导入日志;每个文件使用自己的 Avatar(已观察到) |
| 将漂移归咎于 Based Upon | 待机动画在循环播放时逐渐滑开 | 烘焙 XZ;Based Upon 只负责放置姿势 |
| 参数超出树的范围 | 速度升高,动画却没有变化 | 将参数限制在子项范围内 |
| 头部约束位于胸部之上 | 头部无法对准目标 | 在兄弟节点顺序中将身体放在前面 |
| 摄像机位于相对两侧,且没有提示 | 混合时摄像机穿过头部并翻转 | 两侧都使用 CylindricalPosition |
| 将玻璃或触发器视为墙壁 | 摄像机跳到窗户前 | 使用 Transparent Layers;忽略触发器 |
| 过场期间提高优先级 | 直到过场结束才有变化 | 由 Timeline 控制 Brain |
在编辑器脚本中设置 Priority | Brain 仍使用旧摄像机 | 使用 cam.Prioritize()(已观察到) |
| 拖动时间轴来测试标记或交接 | 标记不会触发;最后一个镜头仍在播放 | 使用 PlayCutscene(已观察到) |
OnNotify 未检查类型 | 对每个标记都会做出响应 | 使用 if (n is MyMarker m) |
| 过早应用 Optimize Game Objects | 场景实例消失 | 在较后阶段、发布前应用(BEZHVYk6Fa4 [00:07:22]) |
更多 Agent 陷阱(归档时 GUID 会变化、每个文件一个类、在 Unity 对象上使用 ??、读取播放模式数据):references/procedures.md。
交接
- 接收: 来自 scenario-blender-export、scenario-maya-expert 或 scenario-3d 的角色 FBX 和动画片段;来自 scenario-unity-architecture 的输入操作;来自 scenario-unity-gameplay 的移动速度、NavMesh Agent 和游戏事件;来自 scenario-unity-pipeline-automation 的导入流水线约定。
- 交付: 向 scenario-unity-gameplay 提供控制器、参数约定(Speed m/s、TurnRate deg/s、IsMoving、Jump)、哈希类、根运动控制器(垂直方向来源);向 scenario-unity-rendering-lighting 提供摄像机切换(Camera Cut 时重置时间效果)和 Timeline 灯光轨道;向 scenario-unity-performance 提供 Animator 数量、剔除模式、导入遮罩、延后应用的 Optimize Game Objects;向 scenario-unity-vfx 提供 Signals 和 Activation 轨道。交付包:项目、作业、 审计 JSON、表格、指标、Verified 和 Assumed 列表。
Unity 6.3 说明
- 6000.3.21f1 清单列出 Cinemachine 2.10.7;直接调用
Client.Add却解析到了 3.1.7(实测): 仍需固定版本。CM3 使用Unity.Cinemachine、CinemachineCamera和组件;CM2 升级时,先将类型改为CinemachineVirtualCameraBase,再执行 Upgrade Entire Project(无法撤销)。在 6.6 中,CM3、Timeline 和 Animation Rigging 将成为核心组件。 - Timeline 1.8:
editorSettings.frameRate。6.3 新增Animator.ResetControllerState。已弃用的ModelImporter成员会在 6.5 中变成错误。 - 模板仅运行 Input System;进入 Play 模式会重新加载域(Play 模式作业会在运行期间将其关闭)。
参考资料
references/expert-notes.md:专家的原则和判断,附来源和时间戳。references/procedures.md:每项作业的参数、背后的 Unity 调用、实时测试和结果。references/critique.md:用于评估骨骼绑定、混合、脚部、摄像机和过场动画的评分标准。references/gui-paths.md:完成相同工作的窗口和菜单。references/sources.md:所有来源、凭据、URL、最佳时间戳和修订历史。