根运动
概述
根运动(Root Motion)是动画编辑器中的一项功能,该功能可以提取动画序列中的根运动数据,运用该数据驱动角色胶囊体移动。
根运动支持提取多个动作融合后的根骨骼动画的增量变换(Delta Transform),并抹除动画中的根骨骼动画。逻辑层基于该特性,可以制作动画驱动的位移表现。
启用根运动
在不启用根运动的时候,骨架网格体和胶囊体是分离的,直接穿过静态网格体并在动画结束后回到最初的位置,角色的动作原点始终在原地。
在启用根运动后,胶囊体保持同步,物理碰撞仍然可以使用。提取动画序列中的根运动数据来驱动角色胶囊体的移动,使角色与静态网格体产生交互,动作坐标原点始终跟随角色移动。角色碰撞到静态网格体后停止位移,此时,动作坐标原点变为角色移动后的位置处。
![]() 不启用根运动 | ![]() 启用根运动 |
根骨骼
角色动画由其骨架网格体的骨骼驱动,在所有骨骼中,根骨骼是整个骨架的基础骨骼。动画中没有动画数据的根骨骼是保持静止不动的,动画在继续播放中,角色本身不在世界坐标中有任何位移。
还有一些动画,其根骨骼是静止的,其他的运动在根骨骼上分配动作,根骨骼进行移动,但是角色本身并不跟随移动,若要角色有位移动作,则需开启根运动。开启根运动后,先锁住根骨骼动画数据,然后将它提取出来应用到角色上。
使用根运动
前置条件
使用根运动功能需要一个包含根骨骼的骨架(组合体(Actor)),同时,该组合体中需要包含一个动画序列,为根骨骼添加动画。
动画序列
使用根运动功能需将每个动画序列的根运动(Root Motion)开启。在动画序列的资产细项(Asset Details)面板中勾选启用根运动(Enable Root Motion),可根据需求修改根运动相关属性。
属性 | 说明 |
---|---|
启动根运动(Enable Root Motion) | 是否开启根运动。 |
根运动根锁定(Root Motion Root Lock) | 根运动提取后,根骨骼的锁定方式。
|
强制锁定根骨骼(Force Root Lock) | 强制锁定根骨骼,无论是否提取过根运动。 |
使用标准化根运动缩放(Use Normalized Root Motion Scale) | 使用归一化的根运动缩放(避免非归一化的缩放对根运动结果的影响)。 |
位移(Translate) | 旧的根运动相关提取设置。可选择清除Z轴(Clear Z-Axis)和清除X、Z轴(Clear X,Z Axes)。 |
动画树
将动画序列中的根运动启用后,还需在动画树编辑器中使用节点来控制管理动画。可将要用到根运动的动画放入动画树中的插槽中。
根运动模式
在将要使用根运动功能的组合体(Actor)中,可以选择不同的根运动模式(Root Motion Mode)。
名称 | 说明 |
---|---|
不抽取(No Extraction) | 不从动画中提取根骨骼运动数据,将其保留在动画姿势中。 |
忽略根运动(Ignore Root Motion) | 提取动画中的根运动,并锁定动画姿势的根变换。但不会缓存提取的根运动数据给上层逻辑使用。 |
来自任何动画(From Everything) | 从任何开启根运动的动画中提取根运动数据,并锁定动画姿势的根变换。会根据来源于动画的各自权重混合并缓存结果供上层逻辑使用。 |
仅来自于蒙太奇(From Montage Only) | 仅从蒙太奇中提取根运动数据,并锁定动画姿势的根变换。会缓存数据供上层逻辑使用。 |
脚本调用播放
actor:BlendAction(“选择播放的动画序列”, false, false, true, 1.0, true, “选择播放插槽”, true),最后一个true表示停止播放同插槽组的其他蒙太奇。
示例
下面为开启根运动后,角色奔跑中遇到墙壁的示例。
创建组合体
参照Actor组装,创建一个包含蒙皮和骨架资产的组合体。
编辑动画资产
在动画编辑器中选中sprint骨架资产后右击,在弹出的快捷菜单中选择将骨架资产转换为动画序列资产(Convert Skeleton To AnimSeq),将该骨架资产转换为一个动画序列资产,然后在弹出的窗口中输入名称后点击确定(OK)按钮完成转换。
在该动画序列的资产细项(Asset Details)面板中,勾选启用根运动(Enable Root Motion)。
编辑完成后,依次点击菜单栏文件(File) -> 保存所有(Save All)进行保存。
配置动画树
在动画编辑器中点击菜单栏文件(File) -> 创建(Create),在弹出的窗口中的下拉框中选择动画树(AnimTree),然后输入名称并选择路径,点击确定(OK)按钮完成创建并进入到动画树编辑器中。
添加一个序列播放节点。在动画树空白处右击打开节点选择面板,展开动画(Animation)选项,选择播放“default_stand”(Play “default_stand”)节点。
在动画编辑器中的插槽管理器(Slot Manager)创建一个默认插槽(DefaultSlot),具体创建步骤可参照动画插槽。
从该动画播放节点引脚处连接一个插槽节点,在弹出的节点选择面板中选择蒙太奇(Montage)选项中刚才所创建的插槽节点。
将该插槽节点连接到最终动画姿势(Final Animation Pose)节点上。
编辑完成后,在动画编辑器中依次点击菜单栏文件(File) -> 保存(Save)。
配置组合体
在项目(Project)面板中,双击组合体(Actor)文件打开组合体编辑器。
在打开的组合体编辑器中,点击资产细项(Asset Details),然后将默认动作(Default Action)设置为所创建的根运动动画树资产,将根运动模式(Root Motion Mode)设置为仅来自于蒙太奇(From Montage Only)。
编辑完成后,在组合体编辑器中依次点击菜单栏文件(File) -> 保存(Save)。
创建角色
在组件编辑器中创建一个关卡,依次点击创建游戏对象(Create Game Object) -> 角色(Character)。
在大纲(Hierarchy)面板中选中该角色对象,然后在观察器(Inspector)面板中选中CharacterMesh0(Inherited),将所创建的组合体(Actor)拖入到骨架网格体配置文件(Skeletal Mesh Config File)的插槽中。
拖入完成:
在观察器(Inspector)面板中,选中CollisionCylinder(Inherited)和CharacterMesh0(Inherited)分别调整该角色胶囊体和网格体的位置,使胶囊体尽可能在包裹角色的前提下,让角色蒙皮的脚部贴地,胶囊体也需在地面上方。
调整角色角度,在观察器(Inspector)面板中勾选该角色的自动控制AI(Auto Control AI)属性。
创建墙壁
在关卡中添加一个墙壁(静态网格体)。从项目(Project)面板中的资源预览窗口中拖拽一个.xmod文件到关卡(Level)中。
根据需要调整该静态网格体的位置和大小。
创建触发器
在关卡中添加一个对象作为触发器。依次点击创建游戏对象(Create Game Object) -> 游戏对象(Game Object),并将该对象重名为RootMotionTrigger。
在大纲面板中选中RootMotionTrigger对象,然后在观察器面板中点击添加组件(Add Component)按钮,选择添加一个胶囊体(Capsule)组件。
在其形状(Shape)选项中可调整该胶囊体的一些相关属性,胶囊体经线数量(Capsule Sides)、胶囊体半球纬线数量(Capsule Half Sphere Rings)、胶囊体半径(Capsule Radius)和圆柱体半高(Cylinder Half Height)。在关卡中调整该胶囊体的位置,使其与角色胶囊体不重叠。
为触发器绑定脚本
为RootMotionTrigger再添加一个脚本(Script)组件。在大纲(Hierarchy)面板中选中该对象,然后在观察器(Inspector)面板中点击添加组件(Add Component)按钮,选择脚本组件(Script Component)。
为该触发器对象绑定一个脚本。编写一个脚本并将其保存在项目资源中的脚本文件夹中。从资源预览窗口中将脚本拖入到该对象脚本组件的脚本文件(Script File)插槽中。
拖入完成:
脚本
local target_actor_name = "LCharacter"
function on_begin_play(component)
local owner = component.GameObjectOwner
nx_bind_script(owner, nx_current())
nx_callback(owner, "on_begin_overlap", "on_begin_overlap")
return 1
end
function on_end_play(component)
end
function on_begin_overlap(pawn, other_actor)
local lscene = nx_value("lscene")
local level = lscene.PersistentLevel
local target_actor = nx_function("ext_find_object", nx_null(), level, target_actor_name)
if not nx_is_valid(target_actor) then
return 0
end
local target_character_mesh_component
for i = 1, target_actor.ComponentCount do
local component = target_actor:GetComponentByIndex(i - 1)
if nx_name(component) == "LSkeletalMeshComponent" then
target_character_mesh_component = component
break
end
end
if not nx_is_valid(target_character_mesh_component) then
return 0
end
local actor = target_character_mesh_component.VisBase
if not nx_is_valid(actor) then
return 0
end
actor:BlendAction("root_motion_sprint_sq", false, false, true, 1.0, true, "DefaultSlot", true)
return 1
end
创建默认Pawn
依次点击创建游戏对象(Create Game Object) -> 默认Pawn(Default Pawn),调整其朝向并将其移动到合适的位置上。
在大纲面板中选中LDefaultPawn,然后在观察器面板中选中LDefaultPawn(Instance),将自动持有玩家(Auto Possess Player)设置为Player 0。
运行
点击运行(Play)按钮即可查看效果。