Facing Warp Node 是一个用于 AnimGraph 的动画节点。它的主要作用是在保持角色下半身运动方向(Locomotion)的同时,动态调整上半身的朝向。
通过在配置好的脊柱骨骼链(Spine Chain)上分布旋转扭曲,该节点能够实现自然的扫射(Strafing)、转身以及锁定目标移动的效果,避免了角色在非直线移动时出现“滑步”或姿态僵硬的问题。
在使用本节点前,理解以下三个核心概念至关重要:
运动与朝向解耦 (Decoupling): 传统的移动往往要求角色面朝移动方向。Facing Warp 允许角色向指定方向移动(Locomotion Direction),但身体面朝前方,通过扭曲脊柱来补偿这两者之间的角度差。
脊柱扭曲分布 (Distributed Twist): 为了避免仅旋转腰部导致的模型变形,该节点将所需的旋转角度按照脊柱骨骼(如 Spine, Chest, UpperChest)在Avatar的层级结构从父到子按权重递增分配旋转角度。
例如旋转角度为90°,设置脊柱骨骼Spine, Chest和UpperChest,权重均为1.0. 计算它们的归一化权重均为1.0/3.0,则在层级结构中位于父级的Spine,其旋转角度为 90°*1.0/3.0 = 30°. 次父级的Chest,其旋转角度为 30° + 90°*1.0/3.0 = 60°. 而位于子级的UpperChest,其旋转角度为 60° + 90°*1.0/3.0 = 90°. 确保角色最终面部朝向为原根运动方向。
输入模式 (Input Modes): 节点支持两种驱动方式:
Direction (方向模式):输入一个目标向量,节点自动计算当前朝向与目标向量的夹角。
Angle (角度模式):直接输入一个具体的角度值(度数)。
以下是在 AnimGraph 中创建并配置 Facing Warp 节点的标准流程:
创建动画输入 (Source) :
在 AnimationNode 分类下找到 AnimationClip 节点并创建。
设置动画:将 Clip 设置为 Ellen_Walk_Forward。
设置循环:确保该动画是循环模式,保证角色持续行走。
创建变量输入 (Input Variable) :
在 Parameters 区域创建一个 Vector3 类型的变量,命名为 MotionDirection。
将其拖入 Graph 视图中,作为一个输入节点。
创建 FacingWarp Node:
在 AnimationNode 分类下找到 AnimationFacingWarpNode 节点并创建。
将 Ellen_Walk_Forward 的 Output (Pose) 连接到 FacingWarp Node 的 Input 端口。
将 MotionDirection 变量节点的 Output 连接到 FacingWarp Node 的 Motion Direction (黄色) 端口。
设置根骨骼 (Setup Root Bone) :指定用于引导根运动的骨骼(通常是 Hips 或 Pelvis)。
配置脊柱骨骼 (Setup Spine Bones) :定义哪些脊柱骨骼参与旋转以及它们的权重。
将下述脚本添加至被相机跟随的游戏对象上。
该脚本获取用户当帧输入的期望 MotionDirection 并传递给 AnimGraph。
using UnityEngine;
using AnimGraph;
public class FacingWarpCharacterController : MonoBehaviour
{
[Header("References")]
public Transform cameraTransform;
[Header("Graph Settings")]
public string paramName = "MotionDirection";
[Header("Rotation Settings")]
public bool lockRotationToCamera = true;
public float turnSpeed = 15f;
public AnimGraphManager graphManager;
void Start()
{
graphManager = GetComponent<AnimGraphManager>();
if (cameraTransform == null)
{
cameraTransform = Camera.main.transform;
}
}
void Update()
{
if (lockRotationToCamera)
{
HandleCharacterRotation();
}
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 moveDir = CalculateCameraRelativeDirection(h, v);
SetGraphParameter(moveDir);
//if (moveDir.magnitude > 0.1f)
// Debug.DrawRay(transform.position + Vector3.up, moveDir * 2, Color.green);
}
void HandleCharacterRotation()
{
Vector3 targetForward = cameraTransform.forward;
targetForward.y = 0;
targetForward.Normalize();
if (targetForward != Vector3.zero)
{
Quaternion targetRotation = Quaternion.LookRotation(targetForward);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * turnSpeed);
}
}
Vector3 CalculateCameraRelativeDirection(float h, float v)
{
if (Mathf.Abs(h) < 0.01f && Mathf.Abs(v) < 0.01f)
return Vector3.zero;
Vector3 camForward = cameraTransform.forward;
Vector3 camRight = cameraTransform.right;
camForward.y = 0;
camRight.y = 0;
camForward.Normalize();
camRight.Normalize();
Vector3 targetDirection = (camForward * v + camRight * h);
if (targetDirection.sqrMagnitude > 0.01f)
{
targetDirection.Normalize();
}
return targetDirection;
}
void SetGraphParameter(Vector3 direction)
{
if (graphManager != null)
{
graphManager.SetVector("MotionDirection", direction);
}
}
}
角色初始播放Walk_Forward动画,向正前方前进。
键盘输入期望运动方向(Motion Direction),角色下半身平滑地转向期望运动方向并前进。
脊柱骨骼根据权重,呈现出自然的扭转曲线,使角色上半身仍朝向正前方,达成运动和朝向解耦的效果。

本节将对编辑器面板(Inspector)中的参数进行详细说明:
开放为端口:如果希望在运行时修改下列参数,可以在Inspector面板的对应属性上单击右键,会弹出“Show As Port”的右键菜单,点击即可开放为端口。连接对应类型的参数可在运行时修改。
| 参数名称 (Inspector) | 描述 |
|---|---|
| Node Weight | 节点总权重 (0.0 - 1.0)。控制整个 Warp 效果的混合程度。1 表示完全应用扭曲,0 表示不生效(直接输出上游动画)。 |
| 参数名称 (Inspector) | 描述 |
|---|---|
| Input Mode | 选择输入模式: Direction: 通过向量计算角度。 Angle: 直接输入角度值。 |
| Use Global Space | (Direction模式) 勾选表示 Motion Direction 使用世界坐标系;不勾选则使用角色局部坐标系。 |
| Motion Direction | (Direction模式) 期望移动方向向量。例如 (1, 0, 0) 代表向右移动。 |
| Locomotion Angle | (Angle模式) 期望的扭曲角度,相对于角色未应用Warp时的根运动方向。 |
| Use Root Motion | 是否启用根运动重定向。勾选后,脊柱的扭曲会影响角色的实际位移方向。 |
| Keep Current Warp | 是否保持当前的扭曲状态。用于在特定状态下(如停止移动瞬间或LocomotionAngle输入为0时)锁定当前的扭曲角度。 |
| 参数名称 (Inspector) | 描述 |
|---|---|
| Warp Offset Angle | 偏移角度:用于调整上半身的朝向,0表示上半身保持原始的根运动方向。 |
| Rotation Axis | 旋转轴:通常设为 Y,表示围绕垂直轴进行水平面上的转身。 |
| Use Smooth Damp | 使用平滑阻尼:勾选后,使用 SmoothDamp 来平滑处理旋转变化避免突兀的转向;未勾选时,使用指数衰减插值平滑处理旋转变化。 |
| Smooth Time | 平滑时间 (秒):控制扭曲响应的滞后感。通常战斗移动建议设为 0.1 - 0.3。 |
| Max Rotation Speed | 最大旋转速度 (度/秒):限制脊柱旋转的角速度上限。 |
| Interp Rotation Speed | 插值旋转速度 (度/秒):控制旋转插值的速度。 |
| Max Rotation Angle | 最大旋转角度 (度):限制脊柱总扭曲角度的绝对值。 |
| 参数名称 (Inspector) | 描述 |
|---|---|
| Root Bone | 根骨骼引用:通常指定为角色的 Hips 或 Pelvis。这是下半身和根运动转向的基础。 |
| Spine Bones |
脊柱骨骼列表:点击 + 号添加。 Transform: 骨骼的 Transform 引用 (如 Spine, Chest, UpperChest)。 Weight: 该骨骼旋转的权重系数。骨骼在列表中的顺序不影响最后的结果,内部会按照骨骼在Avatar中的层级结构从父到子按权重递增分配旋转角度。 |
骨骼权重分配: 建议脊柱骨骼的权重总和接近 1.0,或者根据美术效果递增。
执行顺序: 在 AnimGraph 中,Facing Warp 节点应当连接在之后,但在 IK Node 之前。
Direction 模式 vs Angle 模式:
如果你的角色控制器是基于速度向量驱动的,使用 Direction 模式最方便。
如果你已经计算好了“移动方向”与“瞄准方向”的 Delta Yaw,使用 Angle 模式更直接。
Q: 为什么设置了参数但角色没有任何反应?
A: 请检查以下几点:
Node Weight 是否为 1?
Spine Bones 列表是否为空?
Root Bone 是否正确设置?
Q: 启用 UseRootMotion 后,角色移动方向变乱了?
A: 确保 Root Bone 设置正确(通常是 “Hips” 或 “Pelvis”)。此外,检查 Motion Direction 和 Use Global Space 的组合是否正确表达了你的移动意图。
Q: 角色上半身旋转过度,像麻花一样?
A: 使用 Max Rotation Angle 来硬性限制最大扭曲度。
Q: 能否配合Animator使用?
A: 提供 AnimationFacingWarpPlayable 配合 Animator 使用。
Q: 如何实现快速的转身效果?
A: 调整 Smooth Time 参数至较小值(如 0.001 秒),并确保 Max Rotation Speed 足够高(如 1000 度/秒)即可实现快速转身。通过减小平滑时间并提高最大旋转速度,可以显著提升角色对方向变化的响应速度,从而达到快速转身的效果。这种设置特别适用于需要快速改变方向的战斗或动作场景中。
Q: SmoothDamp与指数衰减插值的区别?
A: SmoothDamp 平滑处理旋转变化时,旋转速度会有缓入缓出的加速减速的过渡,适合模拟物理上的惯性效果;而指数衰减插值则在初始时刻就达到最大旋转速度,响应更快但可能显得生硬。选择哪种方式取决于你希望达到的动画风格和流畅度要求。在实际应用中,SmoothDamp 更常用于需要自然过渡的场景,例如角色行走或跑步时的自然转身;而指数衰减插值则更适合需要即时响应的交互操作,比如快速转向或紧急避让等动作。