Back to list
dev_to 2026年3月7日

Unreal Engineにおける pitches のリピクレーションと軸圧縮

Pitch Replication And Axis Compression In Unreal Engine

Translated: 2026/3/7 7:56:52

Japanese Translation

プレイヤーの見方や狙い目を表示するための pitch リピクレーションは、非常に一般的な作業です。多くのマルチプレイゲームで使用される一部であり、他のプレイヤーがどの方向で視線を向けているのかを理解していることにより、これは必要不可欠です。初級のアーティストたちはインターネットを利用してリピクレート Pitch 値を達成するためのチュートリアルを見つけたでしょう。私は大学時代からその方法を試行錯誤していましたが、Shooter Game でコードを見ると、すでに Unreal Engine 自体に優れた解決策があることに気づきました。Blueprint でも GetBaseAimRotation() を使用することにより pitch 値がリピクレートすることができます。以下の手順を実装してください:Get Base Aim Rotationの出力ベクトルを取得します。自身のワールド・トランスフォームを使用して世界系からローカル系への変換を行います。ベクトルの結果を分割し、pitch を取得します。C++では Kismetライブラリを利用するためにはそれぞれヘッダーが追加してください。この方法を用いて pitch 値をリピクレートするために実装した関数を作ります:FRotator GetReplicatedPitch() const; ファイルの実装部分では次の方法を使用します:float AMyCharacter::GetReplicatedPitch() const { FVector AimDirectionWorld = UKismetMathLibrary::GetForwardVector(GetBaseAimRotation()); FVector AimDirectionLocal = UKismetMathLibrary::InverseTransformDirection(GetActorTransform(), AimDirectionWorld); FRotator AimRotationLocal = UKismetMathLibrary::MakeRotFromX(AimDirectionLocal); return AimRotationLocal.Pitch; } もしくは、Kismet ライブラリではなく C++ のネイティブ関数を使用することにより同じ結果を実現できます:float AMyCharacter::GetReplicatedPitch() const { FVector AimDirectionWorld = GetBaseAimRotation().Vector(); FVector AimDirectionLocal = ActorToWorld().InverseTransformVectorNoScale(AimDirectionWorld); FRotator AimRotationLocal = AimDirectionLocal.Rotation(); return AimRotationLocal.Pitch; } あなたはこれらの操作を行っているのを疑問に思い、それらがどのように機能するのか知りたいでしょう。他の軸や値リピクレーションを行うにも同じメソッドを使用することができます。最も一般的なルートでは GetBaseAimRotation() ファンクショが利用されます。このファンクショは二つのトレイルルに割かれ、プレイヤーのコントールを持っているか否かで分割されます。コントールを準備できている場合は、次のように機能します:FVector POVLoc; FRotator POVRot; コンソールがあれば && !InFreeCam() をチェックし、PlayerViewPoint で視線方向や位置を取得し、それが結果になります。つまり、視線方向のベクトルとワールド・トランスフォームを使用します。もしプレイヤーがコントールを持っているのが確認できなければ、別の計算を行うことが必要となります:FVector POVLoc; FRotator POVRot; これらのどちらも利用可能です: コンソールありの場合に、PlayerViewPoint の出力を取得します。無効であれば ActorToWorld の結果を使用する。そしてこの場合でも、RemoteViewPitch (遠端ビューピッチ) を設定することによりピッチをリピクレートしてからそれを返答します。これはゲームの再帰機能とカリーされたプレイバック機能だけを考慮した時のものであるため、それ以外の状況ではほとんど実行されませんが... もし RemoteViewPitch (遠端ビューピッチ) を利用すれば、一般的なコントールでリピクレートする pitch 値が設定されます。

Original Content

Replicating Pitch for using in aim offsets is a quite a common task to come across while building almost any kind of multiplayer game, you want to replicate the look view of other players to know where they are looking or aiming at. Quite a lot of young developers will search about this on internet and come across tutorials that manually replicate the pitch value from control rotation, this is all well and good and I myself was one of those guys back in university days starting to learn Unreal I also replicated the pitch using the same way, it was not until I came across Shooter Game where upon seeing the source code I realized that a better and more efficient solution already comes with Unreal Engine. You can use the function called GetBaseAimRotation() which exists inside the pawn class to get the replicated pitch in blueprints as well. Follow these steps: Get Base Aim Rotation and Get its forward vector. Inverse transform the direction from world to local space using the world transform of the pawn itself. Break the resultant vector and get pitch. In C++ you can either use the functions provided by Kismet library or the C++ native functions both do the same thing, If using Kismet Library remember to add it’s respective header. Let’s create a function which we can use to get our replicated pitch value: FRotator GetReplicatedPitch() const; In the implementation file: float AMyCharacter::GetReplicatedPitch() const { const FVector AimDirectionWorld = UKismetMathLibrary::GetForwardVector(GetBaseAimRotation()); const FVector AimDirectionLocal = UKismetMathLibrary::InverseTransformDirection(GetActorTransform(), AimDirectionWorld); const FRotator AimRotationLocal = UKismetMathLibrary::MakeRotFromX(AimDirectionLocal); return AimRotationLocal.Pitch; } Or if you don’t want to use Kismet Math Library you can easily do the same thing with native functions: float AMyCharacter::GetReplicatedPitch() const { const FVector AimDirectionWorld = GetBaseAimRotation().Vector(); const FVector AimDirectionLocal = ActorToWorld().InverseTransformVectorNoScale(AimDirectionWorld); const FRotator AimRotationLocal = AimDirectionLocal.Rotation(); return AimRotationLocal.Pitch; } You might be curious that how this works under the hood, you can use the same method for replicating other axis or even other values. As you have seen the method at the core is called GetBaseAimRotation() this function is divided into two paths, if the player has the controller and if the controller isn’t present AKA If it is a simulated proxy. In case of controller being valid the method executes a very simple set of instructions: FVector POVLoc; FRotator POVRot; if( Controller != nullptr && !InFreeCam() ) { Controller->GetPlayerViewPoint(POVLoc, POVRot); return POVRot; } We are just getting the player’s eyes or direction at which the player is looking at. However if the controller is not valid: // If we have no controller, we simply use our rotation POVRot = GetActorRotation(); // If our Pitch is 0, then use a replicated view pitch if( FMath::IsNearlyZero(POVRot.Pitch) ) { // use the RemoteViewPitch const UWorld* World = GetWorld(); // Simulated network driver for recording and playing back game sessions const UDemoNetDriver* DemoNetDriver = World ? World->GetDemoNetDriver() : nullptr; // This is for replay and recording skip this if statement if (DemoNetDriver && DemoNetDriver->IsPlaying() && (DemoNetDriver->GetPlaybackEngineNetworkProtocolVersion() < FEngineNetworkCustomVersion::PawnRemoteViewPitch)) { POVRot.Pitch = RemoteViewPitch; POVRot.Pitch = POVRot.Pitch * 360.0f / 255.0f; } else { // This is the main part, we are just assigning Remote View pitch to pitch and returning it POVRot.Pitch = FRotator::DecompressAxisFromByte(RemoteViewPitch); } } return POVRot; You might get a bit overwhelmed at first but most of this code doesn’t even get the chance to execute in normal circumstances because it is for replay and recording features, the thing we are concerned with is the last else of the if else statements: // This is the main part, we are just assigning Remote View pitch to pitch and returning it POVRot.Pitch = FRotator::DecompressAxisFromByte(RemoteViewPitch); variable called RemoteViewPitch is a replicated member of the class here is how it is declared in the header: UPROPERTY(replicated) uint8 RemoteViewPitch; It’s just a replicated property and another thing that catches the eye is the unsigned integer, in this variable is where our Pitch value is stored in a compressed format. We do the compression in the pre-replication stage, pre-replication is a virtual function that you can override, and this is called on classes of type Actors right before the actual replication occurs. void APawn::PreReplication( IRepChangedPropertyTracker & ChangedPropertyTracker ) { Super::PreReplication( ChangedPropertyTracker ); if (GetLocalRole() == ROLE_Authority && GetController()) { SetRemoteViewPitch(GetController()->GetControlRotation().Pitch); } } The SetRemoteViewPitch is another function inside the Pawn class which just compresses the float axis value into a single byte. void APawn::SetRemoteViewPitch(float NewRemoteViewPitch) { // Compress pitch to 1 byte RemoteViewPitch = FRotator::CompressAxisToByte(NewRemoteViewPitch); } That is all for this topic, I do recommend to go into the pawn class and take a look at these functions again, even if you can’t grasp these fear not as most of time you just will be using the built-in pitch replication for pawns and if you want to compress some other axis the best way to do this is in the pre-replication function. Good Luck!