
1. 先把“动画选取一段使用”这件事拆明白1.1 三种常见情况对应三条完全不同的路在 UE5.5 项目里被问到最多的一个问题往往是“我想从一段动画里选取一段来使用怎么做”。如果只给一个答案十有八九会误导人因为这句话背后通常有三种完全不同的情况策划手里拿到很长的动画资产想让角色只表现其中某个动作片段程序需要在运行时根据玩家输入或玩法上下文切换不同动作项目用数据驱动动画路径写在配置表里运行时需要动态加载后选段播放。这三种情况对应的方案分别是在素材侧重新裁剪/导出动画资产、使用 AnimMontage 的 Section 机制、用软引用配合异步加载来动态播放。它们并不冲突但在同一个项目里往往需要组合使用。我自己的习惯是能用 Montage Section 表达的绝不去硬剪动画文件只有资产本身真的需要瘦身或者要做跨角色重定向时才动 FBX 导出流程。下表是我平时做选型时用的速查依据实际需求推荐方案是否重做资产适合人群从长动画中固定截取一段且不再调整导入时指定 FBX 首尾帧是一次性美术 / TA同一动画内按节奏播放不同小节AnimMontage Section否动画 / 程序运行时根据配置切换任意动画软引用 Montage_Play否程序过场、镜头展示、UI 看板循环动画Sequencer 动画轨道否导演 / 策划另外要提醒一句不要一上来就想着在 UE 里“直接剪辑 AnimSequence”。UE 的动画序列资产本身不是一个视频编辑器它没有“把中间一刀删掉”这种操作。理解这一点比照着教程硬做重要得多。1.2 为什么我优先推荐 Montage SectionMontage 的本质可以理解成“动画编排层”。你可以在同一份 Montage 里把一条或多条 AnimSequence 按逻辑点切成若干段每一段命名为某个 Section然后运行时按名字播放或切换。它不需要复制动画数据内存开销很小还能使用 Slot、混合、Notify、Root Motion 等一系列现成设定。用 Section 做“选取一段”的最大收益是资产不用重复劳动。一条 60 秒的复合动画你可以切成 IDLE、WALK、RUN、TURN_L 等段动画师在编辑器里可以每段单独预览和调整切分点只需要拖一下 Marker 就行完全不需要重新导 FBX。从程序角度看我只要知道 Section 名字就能控制播放不用去关注“第几秒该切到哪一帧”。这样代码和数据层就稳定了外部传入“Attack_02”内部调用 Montage_JumpToSection 或 Montage_Play 的 StartSectionName 参数即可。配上动画通知还能做连招段之间的精确衔接。这套机制在 UE5.5 里已经非常成熟下面我会把整条实操链路一步一步写出来。2. 素材侧处理长动画截段的常用手段2.1 导入 FBX 时直接设置首尾帧最省事但最不灵活如果你手里是 Mixamo、MotionBuilder、Rokoko 这类工具导出的 FBX导入 UE5.5 时可以直接在导入面板里设置 Start Frame 和 End Frame。这个功能处理“固定截段”非常快。比如一段原始动画长度 200 帧你只想保留第 20 到第 80 帧作为某个转身动作导入的时候填好范围生成的 AnimSequence 就只会包含那一段。要注意的地方有三个第一帧号要以源文件实际帧率为准很多外部工具默认 30 FPS 或 60 FPS如果填错范围截出来的段时间就对不上。第二通常我会在首尾多留 3~5 帧作为缓冲否则动画进入 Montage 后做混合动作会显得发紧。第三再次导入时骨骼勾选必须一致尤其是 Skeleton 选项。如果骨骼 Track 对不上最终进引擎的角色可能会以一个非常诡异的姿势播放。为什么说它“最不灵活”因为一旦导入完成想改范围就要重新导一次。如果整个项目还在迭代动作频繁重导必然增加团队沟通成本。所以只有在“这个动作已经定稿未来不改”的情况下我才比较推荐这种方法。2.2 外部 DCC 里切段导出适合精细打磨如果动画本身还需要加工例如去掉不需要的位移、补关键帧、合并骨骼权重我会先把 FBX 放到 Blender 或 MotionBuilder 里处理。Blender 的 Action Editor 可以把一段连续动作拆成多个独立 Action然后在导出时只选择你要的那一段。注意在导出前务必把 IK、约束、物理模拟的结果烘焙成骨骼关键帧否则引擎里不会自动帮你解算那些约束。如果是 Root Motion 动作还要额外检查 Root 骨骼曲线。很多“截段后角色滑步”的问题其实不是引擎设置错了而是 DCC 导出时 Root 骨骼上残留了多余的移动关键帧。我在 Blender 里通常是先选中 Root 骨骼清掉不需要的位移帧再整体 Bake 一次最后导出 FBX 时保持默认的 Bake Animation 选项。2.3 Sequencer 只能控制播放窗口不会真正裁剪资产Sequencer 在 UE5.5 里也是常见的“选取一段并播放”的地方但我有必要把它和“裁剪”区分开。你把 AnimSequence 拖到 Sequencer 里的 Animation Track通过调整轨道时间或 Segment 的起点终点能够实现“这一段动画只展示其中某一段”。这很直观也适合做广告动画、宣传片头、镜头展示等非交互场景。但需要注意Sequencer 做的事情是“决定从动画时间轴里取哪一段来播”并不是修改或复制出另一个 AnimSequence 资产。所以如果你想让角色在游戏运行时也用同一个截取结果这在 Sequencer 里是做不到的。运行时的动画逻辑最终还是得落到 Montage 或 AnimSequence 上。2.4 不要过度依赖剪辑插件很多朋友会问我有没有“一键在 UE 里把动画裁剪成多段”的插件。老实说UE 的动画生态里确实有很多辅助工具比如动画工具插件、Pose 工具、Animation Rest 相关插件等。对基础需求使用原生功能就够了。真正常见的瓶颈其实是“不同角色的骨骼命名不一致”同一套动画要在多个模型上复用这种场景适合用 IK 重定向或 AutoRigger 这类工具做预处理比在引擎里穷折腾小很多。3. 实操流程用 AnimMontage 的 Section 选取一段动画3.1 创建 Montage 并规划 Section 分组假设我现在有一条角色攻击动画想拆成“起手 / 中段 / 收尾”三段还希望随时能单独播放其中某一段。操作流程是这样的在内容浏览器选中这条 AnimSequence右键选择 Create Anim Montage。这会生成一个默认的 Montage 资产并把动画放进去。双击打开 Montage 编辑器在动画时间轴上方能看到一条 Segment。把播放头拖到要切分的帧位置右键选择添加 Section Marker把它切成多个段落。每个 Segment 会自动生成 Section 名称默认叫 Section 1、Section 2 等等。我非常不建议保留默认名直接改成更有业务意义的字符比如 Attack_Start、Attack_Main、Attack_End大小写和拼写规则全团队强制一致。Section 的命名很关键因为蓝图和 C 都是按字符串匹配的。我见过太多因为 Attack_start 和 Attack_Start 不一致导致按钮按了没反应、动画从头重播这种低级事故。后面如果要对接技能配置表建议直接把 SectionName 作为表单字段让策划也能参与配置。3.2 在动画蓝图里正确接线 Slot 节点Montage 创建完成后还不能直接在角色上播放。打开角色的动画蓝图在 AnimGraph 里找到 Slot 节点并拖到图表中。Slot 节点的属性里有一个 Slot Name必须和 Montage 详情面板里的 Slot 名称完全一致。如果你用的是默认 DefaultSlot那两边都填 DefaultSlot。为什么一定要经过 Slot因为 Slot 是 Montage 和动画蓝图之间的“插槽”。Montage 不会直接抢走动画蓝图的状态机输出而是通过 Slot 把当前 Montage 段和底层动画做混合。Blend In / Out 的时间就控制了这个过渡过程的柔和程度。如果 Slot 没连上或者名称不一致你调用 Montage_Play 也会发现角色毫无变化。混合参数上给一个可复用的经验普通待机切换到攻击Blend In / Out 设 0.1~0.2 秒手感比较利落受击、移动转向这类动作可以略长如果是瞬移、换枪等强调瞬间反应的动作可以压到 0.05 秒甚至 0。别小看这个参数很多人“动画播放卡一下”其实就是这里没调好。3.3 在蓝图中按 Section 名播放指定片段在角色蓝图里获取动画实例后调用 Montage Play 节点在参数里传入 Montage 资产。这时你会看到一个 Start Section 输入把它填成你想播放的 Section 名称。比如上面命名的 Attack_Main运行时角色就会直接从这个中段动作开始播放而不是从头起手。这一步就是最直接回答“如何选取一段使用”的方式。如果要控制流程比如起手段播完自动接中段就用 Montage Set Next Section 节点。它有两个关键输入当前 Section 名和目标 Section 名。实际使用中我通常在前一段快要结束时通过动画通知触发这个切换这样能在节奏上卡得很准而不需要手动算帧数。3.4 C 侧的调用与参数说明如果项目里动画触发逻辑写在 C 里标准写法大致是这样UAnimMontage* Montage LoadObjectUAnimMontage(nullptr, TEXT(/Game/Character/Animation/AM_Attack.AM_Attack)); if (!Montage) { return; } UAnimInstance* AnimInstance GetMesh()-GetAnimInstance(); if (AnimInstance) { AnimInstance-Montage_Play(Montage, 1.0f); // 直接从“中段”这个 Section 开始播放 AnimInstance-Montage_JumpToSection(TEXT(Attack_Main), Montage); // 或者当前段播放结束后自动切换到下一段 AnimInstance-Montage_SetNextSection(TEXT(Attack_Main), TEXT(Attack_End), Montage); }这里要注意 Montage_Play 的第一个参数是播放速率1.0 表示原始速度第三个参数默认是 MontageLength一般情况下不用关心。Montage_JumpToSection 用于“瞬间切到指定段”不会等待当前段播完而 Montage_SetNextSection 是“排队切换”适合连续技。这两种用法的语义一定要分清楚否则会出现切段后动画直接从目标段起始帧开始播而不是从当前段自然过渡过去的情况。4. 进阶动态加载与程序化截取的实战技巧4.1 用软引用异步加载动画资产在一些项目里动画路径来自数据表或远端配置不是编译时写死的。如果直接用 LoadObject 同步加载小资产还好假如加载的是一堆高品质 Montage会在主线程卡一下而且很难维护。建议配置表字段使用 TSoftObjectPtr运行时用异步加载。一个比较常见的 C 写法是#include Engine/StreamableManager.h TSoftObjectPtrUAnimMontage MontagePtr FSoftObjectPath(TEXT(/Game/Character/Animation/AM_Attack.AM_Attack)); FStreamableManager StreamableManager UAssetManager::GetStreamableManager(); TSharedPtrFStreamableHandle Handle StreamableManager.RequestAsyncLoad( MontagePtr.ToSoftObjectPath(), FStreamableDelegate::CreateLambda([this, MontagePtr]() { UAnimMontage* LoadedMontage MontagePtr.Get(); if (LoadedMontage GetMesh() GetMesh()-GetAnimInstance()) { GetMesh()-GetAnimInstance()-Montage_Play(LoadedMontage, 1.0f); } }) );在蓝图中对应的节点是 Load Asset 或 Load Asset Async。用异步加载的好处是在游戏包体比较大的项目里角色触发一个技能时不会因为资源没到位导致角色原地卡住。注意在资产还没加载完成时不要调用播放如果必须提前调用就给一个默认兜底动画。4.2 用播放时间参数做“临时掐段”还有一种取巧方式在 Montage_Play 里传入起始时间秒然后通过 Montage_Stop 在指定时间停止。它可以在不新建资产的情况下从时间轴上截出想要的片段。这对调试很有用我在检查动画节奏时经常这么干先放整条走一遍再直接按时间掐到指定区间快速确认是不是想要的段落。但它有两个明显缺陷第一如果你使用 Section 机制StartTime 和 Section 切换之间容易产生冲突因为 Section Marker 是按逻辑段走的StartTime 会把播放头带到时间轴中间后续的 Section 切换逻辑会变得很怪。第二停止时如果时间选得不好动作容易被硬生生“钉”在半途。所以我只把这种方式当临时调试工具正式逻辑里还是优先用 Section。4.3 根骨骼与 Root Motion拼接段时不滑步的关键“截段后滑步”是各类 UE 动画项目里最经典的问题。做完“选取一段”的拼接后人物位移要么该走不走要么原地滑步。排查时优先看两件事。第一AnimSequence 的 Root Motion 开关是否一致。在动画序列资产详情面板Root Motion 选项会决定位移是否被引擎当作根骨骼移动处理。如果某些段开着 Root Motion、某些段关着拼接时速度曲线会跳变。第二根骨骼曲线本身是否干净。外部 DCC 导出的 FBXRoot 骨骼上经常残留大量多余的移动关键帧哪怕你只是截取中段这些位移依然会被播放出来。所以如果动作本身是原地动画比如攻击、受击、技能施法最好关闭 Root Motion靠代码控制角色移动如果是翻滚、冲刺、击退这类需要有真实位移的动画必须保证所有相关 Section 都打开 Root Motion并把过渡段的速度曲线修平。这个原则比记忆任何节点参数都重要。4.4 用动画通知做多段连击切换做战斗连招时Section 机制非常顺手。我一般把三个攻击动作放在同一个 Montage 里分别命名 Attack_1、Attack_2、Attack_3。在每个攻击段的命中帧附近添加动画通知通知里判断是否收到下一次攻击输入。如果收到输入调用 Montage_SetNextSection把当前段切到下一段没收到输入当前段播完角色自然回到待机状态。这个方案的优点是判断输入不用写死帧时间只要有通知触发就说明播放已经到达某个节奏点切换时机天然准确。再加上 Montage_Stop、Blend Out 等控制手感可以调得比较细腻。如果你的项目里角色有很多技能这套“Montage Section Notify”就是最标准的扩展模型。5. 常见问题与实测排查清单5.1 动画播不出来或者只从头播放原因基本集中在三处Montage 资产里的 Section 名与你传入的字符串不匹配蓝图节点里的 Start Section 下拉没有选中正确名称C 调用顺序不对。建议先在编辑器里打开 Montage 的 Section 列表把实际名字列出来再进代码或蓝图里核对。还有一个容易被忽略的坑如果 Montage 刚创建时只默认生成一个 Section你忘了添加 Marker那再怎么传 Section 名都不会生效。5.2 播放时被其他动画覆盖问题常常出在动画蓝图的输出姿势上。Slot 节点必须放在正确的混合链路上且没有被其他更高优先层的姿势覆盖。如果同时用了多个 Slot要注意它们之间的 Blend 顺序。全项目最好统一使用一个 DefaultSlot只有需要同时播放面部动画、武器动画等特殊场景时再增加 Slot 并明确优先级管理。5.3 截出来的段落地后位置乱跳优先检查 Root Motion 开关和根骨骼曲线。如果角色位移是由 Root Motion 驱动的每个 Section 的位移曲线都要保持一致如果角色位移由移动组件驱动动画里就不要再带 Root Motion。这两者混用的后果是“双重位移”角色会莫名飘出很远。另一种情况是同一根骨骼上带了 Scale 关键帧这种问题相对隐蔽但也会影响角色位置的中间计算需要去动画资产里检查关键帧列表。5.4 路径加载失败或播放瞬间卡顿数据表路径里只要多一个空格、少一个点异步加载就可能失败。建议在加载回调里输出日志确认路径是否正确。如果播放瞬间卡顿通常是因为用了同步 LoadObject资源太大时会在主线程阻塞。程序化项目里建议全部改成流式加载能明显减少战斗瞬间的掉帧。5.5 快速排查表现象最可能原因优先检查位置Montage 播放无反应Slot 名称不匹配 / AnimGraph 未接 SlotMontage 详情面板、动画蓝图 AnimGraph一直从头播跳不到指定段Section 名写错 / 未创建 MarkerMontage Section 总览播着播着被其他动画盖住其他动画状态持续输出姿势状态机、Blend 优先级位移跳变 / 滑步Root Motion 开关不一致动画序列详情、根骨骼曲线异步加载后动画空引用路径错误或未等待加载完成数据表路径、加载回调6. 我实际用下来最值得记住的三件事第一件判断要不要动素材核心标准是“它是不是同一个资产里的逻辑子段”。同一个资产里的多个用途优先用 AnimMontage Section只有资产本身需要瘦身或者真的用于跨角色复用才去重新导出。第二件命名规划要放在技术实现之前。Section 名、Slot 名、动画资产路径这些字符串如果不统一调试时间会被无限拉长。我甚至会在项目的技术规范文档里把命名规则写成硬性要求并且用自定义前缀约束所有新增动画资产。第三件UE5.5 自带的模板工程里就有现成的 Montage 用法。第三人称模板的动画蓝图里包含一个 DefaultSlot 的接线逻辑在编辑器里拆开看一遍比看很多篇图文教程都更直接。我每次新建项目都会先把模板里的 Montage 资产翻出来看一眼确认当前版本的接口有没有变化然后再开始写自己的逻辑。这一套组合方式基本能解决绝大多数“从整条动画里选取一段使用”的场景也是我在动作向项目上踩过不少坑之后沉淀下来的流程。