반응형

위와 같이 각 Pawn에 대해 SetViewTarget 를 하면 다음과 같다.

 

void AActor::CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult)
{
	if (bFindCameraComponentWhenViewTarget)
	{
		// Look for the first active camera component and use that for the view
		TInlineComponentArray<UCameraComponent*> Cameras;
		GetComponents(/*out*/ Cameras);

		for (UCameraComponent* CameraComponent : Cameras)
		{
			if (CameraComponent->IsActive())
			{
				CameraComponent->GetCameraView(DeltaTime, OutResult);
				return;
			}
		}
	}

	GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
}

내부 동작을 확인해보면 CameraComponent 가 존재하면 해당 뷰 값을 가져오지만 없으면 1인칭 으로 빠지는것을 확인할 수 있다.

 

그리고 저 OutResult 을 올라가보면 다음과 같은 구조체를 볼 수 있다.

/** A ViewTarget is the primary actor the camera is associated with. */
USTRUCT(BlueprintType)
struct FTViewTarget
{
	GENERATED_USTRUCT_BODY()
public:

	/** Target Actor used to compute POV */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TViewTarget)
	TObjectPtr<class AActor> Target;

	/** Computed point of view */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TViewTarget)
	struct FMinimalViewInfo POV;

protected:
	/** PlayerState (used to follow same player through pawn transitions, etc., when spectating) */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TViewTarget)
	TObjectPtr<class APlayerState> PlayerState;
    ...(생략)

POV (Point of View) 는 관점 / 시점 뭐 이런뜻이고 카메라의 위치 회전 FOV 직교여부 클리핑 등 카메라에 대한 정보를 담고 있다.

 

 그리고 이 ViewTarget은 PlayerCameraManager가 가지고 있다.

 

아까 CalcCamera 함수를 타고 올라가면 PlayerCameraManager 의 UpdateViewTarget이라는 긴 함수가 있는데

CameraStyle에 따라 ThirdPerson / Freecam / Fixed 등 하는 방식은 다르지만 현재 ViewTarget 기준으로 이번 프레임의 POV 를 계산한다.

 

즉, SetViewTarget으로 어떤 대상(Target)을 정하고 해당 대상으로 부터 (POV) 를 계산하여 PlayerCameraManager의 FViewTarget ViewTarget 에 저장된다.

-> 카메라 값 (POV) 를 계산하는데 있어 어떤 대상을 기준으로 계산할 것인가

 

이 카메라의 POV의 Loc 과 Rot는 월드상의 Loc / Rot 랑 같은것이다.

 

정리하면, SetViewTarget을 하기위해 Camera는 필수적이지 않다.

하지만 대상을 원하는 시점으로 보려면 SpringArm / Camera 의 조합으로 해당 카메라로부터 POV를 계산하거나

혹은 Target과 POV 를 통해 해당 액터를 보는것이 가능하다.

 

 

동기화

APlayerCameraManager::UpdateCamera 에선 카메라 위치 / 회전(Roll 제외) 값만 서버로 전달한다.

말 그대로 전달만 하기 때문에 클라이언트에 레플리케이션작업은 따로 해주어야 한다.

// compress the rotation down to 4 bytes
int32 const ShortYaw = FRotator::CompressAxisToShort(CurrentPOV.Rotation.Yaw);
int32 const ShortPitch = FRotator::CompressAxisToShort(CurrentPOV.Rotation.Pitch);
int32 const CompressedRotation = (ShortYaw << 16) | ShortPitch;

int32 const PrevShortYaw = FRotator::CompressAxisToShort(LastPOV.Rotation.Yaw);
int32 const PrevShortPitch = FRotator::CompressAxisToShort(LastPOV.Rotation.Pitch);
int32 const PrevCompressedRotation = (PrevShortYaw << 16) | PrevShortPitch;

if ((CompressedRotation != PrevCompressedRotation) || !ClientCameraPosition.Equals(PrevClientCameraPosition) || (TimeSinceLastServerUpdateCamera > ServerUpdateCameraTimeout))
{
    PCOwner->ServerUpdateCamera(ClientCameraPosition, CompressedRotation);

    TimeSinceLastServerUpdateCamera = 0.0f;
}

내부에선 SetCameraCachePOV 를 통해 저장되고 GetCameraCacheView 를 통해 최신 POV 값을 가져올 수 있다.

또한 if문에서 이전값과 다르거나 TimeOut 이 지나면 (기본값 2초) 서버로 보낸다.

 

Client -> Server Server -> Client

ServerUpdateCamera 함수를 오버라이드하여 오른쪽 방식처럼 Rep 받는 액터를 만들고 FMinimalViewInfo 를 Rep 하면 다른 클라이언트가 보고있는 장면 (POV) 를 받아 적용할 수 있다. [ex 데스캠]

반응형

'언리얼' 카테고리의 다른 글

Zen Storage  (0) 2025.12.31
DerivedDataBackendGraph  (0) 2025.12.24
Deproject 위젯 -> 월드  (1) 2025.11.18
World Widget Depth Test  (0) 2025.09.24
Custom Depth Stencil Pass  (0) 2025.09.19

+ Recent posts