Pitch Replication And Axis Compression In Unreal Engine

Published: (March 7, 2026 at 02:25 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

The Pawn Class

The function GetBaseAimRotation() (available in the APawn class) returns the replicated pitch and can be used both in Blueprints and C++.

Blueprint Steps

  1. Call Get Base Aim Rotation and obtain its forward vector.
  2. Inverse‑transform that direction from world space to the pawn’s local space (using the pawn’s world transform).
  3. Break the resulting vector and read the Pitch component.

Aim offset diagram


C++ Implementation

You can either use the Kismet Math Library or the native vector/rotator functions—both approaches give the same result.
Remember to include the appropriate header if you use the Kismet library (#include "Kismet/KismetMathLibrary.h").

// MyCharacter.h
class AMyCharacter : public ACharacter
{
    // ...

    /** Returns the replicated pitch value. */
    float GetReplicatedPitch() const;
};

Using Kismet Math Library

// 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;
}

Using Native Functions

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;
}

Both versions return the same pitch value that is replicated from the owning client.


Under the Hood

GetBaseAimRotation() works differently depending on whether the pawn has a valid controller (i.e., it is locally controlled) or not (i.e., it is a simulated proxy).

When a Controller Exists

FVector POVLoc;
FRotator POVRot;

if (Controller != nullptr && !InFreeCam())
{
    Controller->GetPlayerViewPoint(POVLoc, POVRot);
    return POVRot;          // Use the player’s actual view rotation
}

The function simply returns the controller’s current view rotation.

When No Controller Exists (Simulated Proxy)

// Use the pawn’s own rotation as a fallback
POVRot = GetActorRotation();

// If the pitch is zero we fall back to the replicated RemoteViewPitch
if (FMath::IsNearlyZero(POVRot.Pitch))
{
    const UWorld* World = GetWorld();
    const UDemoNetDriver* DemoNetDriver = World ? World->GetDemoNetDriver() : nullptr;

    // Replay/recording path – ignore for normal gameplay
    if (DemoNetDriver && DemoNetDriver->IsPlaying() &&
        DemoNetDriver->GetPlaybackEngineNetworkProtocolVersion() GetControlRotation().Pitch);
    }
}
  • SetRemoteViewPitch converts the floating‑point pitch into a byte (uint8) using FRotator::CompressAxisToByte.
  • On the client side, GetBaseAimRotation() expands that byte back into a full float pitch with FRotator::DecompressAxisFromByte.

Summary

  • Use GetBaseAimRotation() to obtain the replicated view rotation.
  • Transform the forward vector to local space and extract the pitch (either via Kismet Math Library or native functions).
  • Under the hood, Unreal compresses the pitch into a single byte (RemoteViewPitch) on the server and decompresses it on remote clients, making the replication cheap and efficient.

You can apply the same pattern to replicate other axes or custom values by adding your own replicated, compressed variables and handling them in PreReplication.

Replicating Pawn Pitch in UE4

Below is the relevant code for handling pitch replication inside a pawn class.

1. Getting the Remote View Pitch

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. Setting the Remote View Pitch

void APawn::SetRemoteViewPitch(float NewRemoteViewPitch)
{
    // Compress pitch to 1 byte
    RemoteViewPitch = FRotator::CompressAxisToByte(NewRemoteViewPitch);
}

Note: SetRemoteViewPitch compresses a float axis value into a single byte for network transmission.


How to Use This

  1. Inspect the pawn class – Open the pawn’s source file and locate the two functions above.
  2. Understand the flow
    • SetRemoteViewPitch is called on the server (or owning client) to compress the pitch before it is replicated.
    • GetRemoteViewPitch (or the corresponding getter you implement) decompresses the byte back into a usable float on remote machines.
  3. Leverage built‑in replication – In most cases you’ll rely on UE4’s default pitch replication for pawns.
  4. Custom axis compression – If you need to compress another axis, follow the same pattern: compress in a pre‑replication function and decompress when reading the replicated value.

Final Thoughts

Even if the details feel a bit overwhelming at first, revisiting these functions in the pawn class will help solidify your understanding. Most of the time the engine’s built‑in pitch replication is sufficient, but knowing how to manually compress an axis gives you flexibility for custom networking needs.

Good luck!

0 views
Back to Blog

Related posts

Read more »

Visualizer Components

Visualizer Components Visualizer components are editor‑only components that draw non‑rendering debug information to the screen or HUD. They are lightweight, mo...

Unreal Engine 3D Fluid To Flipbook

I always wanted to create blood VFX using alembics, but those simulations can become very large and are impractical for many games. Unreal Engine includes a bui...

Move Semantics In Unreal Engine

The Copy Problem In traditional C++98 programming you had two ways in which objects were created: from scratch and from copying. cpp Foo; // Default ctor Fooin...