输入控制与视角层级结构

1. 输入是如何控制Pawn和Camera的

Rotation部分: 所有的输入首先会通过AddPitch/Yaw/RollInput修改RotationInput。
RotationInput记录了每帧的输入变化。在PlayerController TickActor->PlayerTick->UpdateRotaton 中通过
PlayerCameraManager->ProcessViewRotation(DeltaTime, ViewRotation, DeltaRot);
累加给ViewRotation,之后赋值给ControlRotation。当帧会清0

修改ControlRotation。各个地方从ControlRotation中获取自己的信息。在给之前会先通过PlayerCameraManager对Rotation进行限制(例如Pitch)。

  • Pawn的Rotation: 在Controller的UpdateRotation调用时,通过调用Pawn的FaceRotation函数进行更新。内部通过bUseControllerRotationPitch/Yaw/Roll参数,来指定获取ControlRotation的一部分或全部。
    • 第一人称视角(FPP) 通常只获取Yaw,这样Pawn的Yaw会和输入保持同步。
  1. 移动输入影响ControlInputVector(在Pawn上),通过APawn::AddMovementInput
  2. UCharacterMovementComponent::TickComponent开头通过ConsumeInputVector,清空并返回ControlInputVector
  3. 返回值会作为Scale缩放最大加速度来得到Acceleration,发生在UCharacterMovementComponent::ControlledCharacterMove,这里也触发JumpInput(但不改变加速度,直接修改Velocity.Z)。
  4. 如果是联机的客户端,该函数会调用ReplicateMoveToServer(DeltaSeconds, Acceleration);内部调用PerformMovement移动。

蹲下输入1p和DS在Movement执行前执行UCharacterMovementComponent::UpdateCharacterStateBeforeMovement。3p通过Rep函数触发。


2. FPP视角下,Camera和FPP Mesh的层级结构

将SpringArm挂在Capsule上,并调整到预期的Camera位置。将FPP Mesh挂在SpringArm上,将其Root与TPP mesh的Root对齐。将Camera挂在FPP Mesh的CameraBone上。

原因:

  1. Camera需要挂在FPP Mesh的CameraBone上,方便Camera动画制作。这样,Camera的旋转由FPP Mesh决定。这就要求输入(即ControlRotation)能够旋转FPP Mesh。
  2. FPP Mesh通常具备完整的人形骨骼,其Root点也位于双脚中间。直接旋转FPP Mesh会导致绕Root旋转。我们希望看起来是Camera在原地旋转(实际上Camera也有自身的晃动,所以不能让Camera带着Mesh转)。
  3. 因此,增加一个中间层级——目前是使用SpringArm。将SpringArm和Camera对齐。旋转SpringArm时,FPP Mesh和Camera保持相对不变,从而实现Camera带着Mesh转的效果。

Camera 的Transform会通过RPC:ServerUpdateCamera 发送给Server,需要在PlayerCameraManager上勾选bUseClientSideCameraUpdates

思考题

如果没有SpringArm,如何通过调整FPP原点的Transform,达到上述Camera原地旋转的效果?

分析:
需要找出Camera的Transform和FPP原点的Transform之间的关系。由于上述层级结构,Camera的世界变换记为,相对于FPP原点的变换记为,FPP原点的世界变换记为,则有:

即:

只需根据需求设置好,再利用上述公式计算出即可。


延伸问题:
类似的问题很多,已知子节点的目标变换,但希望通过调整某个父节点的变换来实现。

设最终父节点的世界变换为,目标子节点的世界变换为,相对世界变换为,中间父节点相对变换为、等(假设有两层)。

首先正向思考:

将中间层级的相对变换记为,则:

对Camera的Transform依赖导致跟不上Camera
比如枪上的激光,要命中准心位置,需要知道Camera的朝向做Trace来得知。
CameraManager的更新在 Post Physics 之后,Post UpdateWork 之前。提前获取的Camera位置可能不准确,可以在Post UpdateWork阶段进行纠正