Pitch 复制与轴压缩在 Unreal Engine 中
Source: Dev.to
请提供您希望翻译的正文内容(除代码块和 URL 之外的文字),我将把它翻译成简体中文并保持原有的 Markdown 格式。
Pawn 类
函数 GetBaseAimRotation()(在 APawn 类中可用)返回复制的俯仰角,可在 Blueprint 和 C++ 中使用。
Blueprint 步骤
- 调用 Get Base Aim Rotation 并获取其前向向量。
- 将该方向从世界空间逆变换到 Pawn 的局部空间(使用 Pawn 的世界变换)。
- 拆分得到的向量并读取 Pitch(俯仰)分量。

C++ 实现
您可以使用 Kismet 数学库或原生的向量/旋转器函数——两种方法得到的结果相同。
如果使用 Kismet 库,请记得包含相应的头文件(#include "Kismet/KismetMathLibrary.h")。
头文件
// MyCharacter.h
class AMyCharacter : public ACharacter
{
// ...
/** Returns the replicated pitch value. */
float GetReplicatedPitch() const;
};使用 Kismet 数学库
// MyCharacter.cpp
float AMyCharacter::GetReplicatedPitch() const
{
// World‑space aim direction from the replicated rotation
const FVector AimDirectionWorld = UKismetMathLibrary::GetForwardVector(GetBaseAimRotation());
// Convert to pawn‑local space
const FVector AimDirectionLocal = UKismetMathLibrary::InverseTransformDirection(
GetActorTransform(),
AimDirectionWorld
);
// Build a rotator from the local X axis and read Pitch
const FRotator AimRotationLocal = UKismetMathLibrary::MakeRotFromX(AimDirectionLocal);
return AimRotationLocal.Pitch;
}使用原生函数
float AMyCharacter::GetReplicatedPitch() const
{
// World‑space aim direction from the replicated rotation
const FVector AimDirectionWorld = GetBaseAimRotation().Vector();
// Convert to pawn‑local space (no scaling)
const FVector AimDirectionLocal = ActorToWorld().InverseTransformVectorNoScale(AimDirectionWorld);
// Build a rotator from the local vector and read Pitch
const FRotator AimRotationLocal = AimDirectionLocal.Rotation();
return AimRotationLocal.Pitch;
}两种实现都会返回从拥有客户端复制过来的相同 Pitch 值。
内部工作原理
GetBaseAimRotation() 的行为会根据 pawn 是否拥有有效的控制器(即本地受控)或没有(即模拟代理)而不同。
当存在控制器时
FVector POVLoc;
FRotator POVRot;
if (Controller != nullptr && !InFreeCam())
{
Controller->GetPlayerViewPoint(POVLoc, POVRot);
return POVRot; // 使用玩家实际的视角旋转
}该函数直接返回控制器当前的视角旋转。
当不存在控制器(模拟代理)时
// 使用 pawn 自身的旋转作为回退
POVRot = GetActorRotation();
// 如果俯仰角为零,则回退到复制的 RemoteViewPitch
if (FMath::IsNearlyZero(POVRot.Pitch))
{
const UWorld* World = GetWorld();
const UDemoNetDriver* DemoNetDriver = World ? World->GetDemoNetDriver() : nullptr;
// 回放/录制路径 – 正常游戏中忽略
if (DemoNetDriver && DemoNetDriver->IsPlaying() &&
DemoNetDriver->GetPlaybackEngineNetworkProtocolVersion() GetControlRotation().Pitch);
}
}SetRemoteViewPitch使用FRotator::CompressAxisToByte将浮点数俯仰角压缩为一个字节 (uint8)。- 在客户端,
GetBaseAimRotation()使用FRotator::DecompressAxisFromByte将该字节解压回完整的float俯仰角。
摘要
- 使用
GetBaseAimRotation()获取已复制的视角旋转。 - 将前向向量转换到局部空间并提取俯仰角(可通过 Kismet Math Library 或原生函数实现)。
- 在底层,Unreal 会在服务器上将俯仰角压缩为单字节(
RemoteViewPitch),并在远程客户端解压,从而实现低成本、高效的复制。
你可以通过添加自定义的已复制、压缩变量并在 PreReplication 中处理它们,将相同的模式应用于复制其他轴或自定义数值。
在 UE4 中复制 Pawn 的俯仰角
下面是处理 pawn 类内部俯仰角复制的相关代码。
1. 获取远程视图俯仰角
void APawn::GetRemoteViewPitch()
{
// Example of retrieving the remote view pitch
float Pitch = RemoteViewPitch; // RemoteViewPitch is a byte
float DecompressedPitch = FRotator::DecompressAxisFromByte(Pitch);
// Use DecompressedPitch as needed…
}2. 设置远程视图俯仰角
void APawn::SetRemoteViewPitch(float NewRemoteViewPitch)
{
// Compress pitch to 1 byte
RemoteViewPitch = FRotator::CompressAxisToByte(NewRemoteViewPitch);
}Note:
SetRemoteViewPitch将float轴值压缩为单个字节,以便在网络上传输。
使用方法
- 检查 pawn 类 – 打开 pawn 的源文件,定位上述两个函数。
- 理解流程 –
SetRemoteViewPitch在服务器(或拥有客户端)上调用,以在复制前压缩俯仰角。GetRemoteViewPitch(或你实现的相应 getter)在远程机器上将字节解压回可用的float。
- 利用内置复制 – 在大多数情况下,你可以依赖 UE4 对 pawn 的默认俯仰角复制。
- 自定义轴压缩 – 如果需要压缩其他轴,遵循相同的模式:在 复制前 的函数中压缩,在读取复制值时解压。
最后思考
即使一开始细节看起来有些繁琐,重新审视 pawn 类中的这些函数也能帮助你巩固理解。大多数情况下,引擎自带的俯仰角复制已经足够,但了解如何手动压缩轴可以为自定义网络需求提供灵活性。
祝你好运!