Skip to content

相机系统

整体流程

UE的相机系统相比于更加复杂,涉及到 CameraComponentCameraActorPlayerControllerPlayerCameraManager 几个类。

classDiagram
    UWorld --> APlayerController
    UGameViewportClient --> ULocalPlayer : 渲染画面时获取摄像机的POV
    ULocalPlayer --> APlayerController : 获取POV
    APlayerController "1" <--> "1" APlayerCameraManager : APlayerController创建并驱动PlayerCameraManager
    APlayerCameraManager ..> AActor : 更新ViewTarget
    AActor o--> UCameraComponent : 计算POV
    APlayerCameraManager <--> UCameraModifier : 最后修改POV
    UCameraModifier --> UCameraModifier_CameraShake : 示例说明

    class UWorld {
        +Tick(...)
    }

    class UGameViewportClient {
        +Draw()
    }

    class ULocalPlayer {
        +CalcSceneView(...)
        +GetViewPoint(...)
    }

    class APlayerController {
        +SpawnPlayerCameraManager()
        +UpdateCameraManager()
        +GetPlayerViewPoint(...)
    }

    class APlayerCameraManager {
        +UpdateCamera(...)
        +UpdateViewTarget(...)
        +GetCameraCacheView()
    }

    class AActor {
        +CalcCamera()
    }

    class UCameraComponent {
        +GetCameraView(...)
    }

    class UCameraModifier {
        +ModifyCamera()
    }

    class UCameraModifier_CameraShake {
    }
  1. CameraActor
    1. CameraComponent 的包装容器,以使相机可以放置在关卡中。
  2. CameraComponent
    1. 代表相机的各种数据。
    2. 并不直接处理数据。
  3. PlayerCameraManager
    1. 相机系统的核心,处理相机数据并应用到 ViewTarget
    2. 管理 ViewTarget,记录摄像机跟随对象Target和摄像机POV。

总体流程上:

初始化ViewTarget

PlayerController 会在 PostInitializeComponents 函数中调用 SpawnPlayerCameraManager 函数。

APlayerController::SpawnPlayerCameraManager
// servers and owning clients get cameras
// If no archetype specified, spawn an Engine.PlayerCameraManager.  NOTE all games should specify an archetype.
FActorSpawnParameters SpawnInfo;
SpawnInfo.Owner = this;
SpawnInfo.Instigator = GetInstigator();
SpawnInfo.ObjectFlags |= RF_Transient;  // We never want to save camera managers into a map
if (PlayerCameraManagerClass != NULL)
{
    PlayerCameraManager = GetWorld()->SpawnActor<APlayerCameraManager>(PlayerCameraManagerClass, SpawnInfo);
}
else
{
    PlayerCameraManager = GetWorld()->SpawnActor<APlayerCameraManager>(SpawnInfo);
}

if (PlayerCameraManager != NULL)
{
    PlayerCameraManager->InitializeFor(this);
}
else
{
    // log
}
每个 PlayerController 都会在世界创建一个 PlayerCameraManager Actor。

针对每个创建的 PlayerCameraManager,都会调用 InitializeFor 函数初始化。

APlayerCameraManager::InitializeFor
FMinimalViewInfo DefaultFOVCache = GetCameraCacheView();
DefaultFOVCache.FOV = DefaultFOV;
SetCameraCachePOV(DefaultFOVCache);

PCOwner = PC;

SetViewTarget(PC);

// set the level default scale
SetDesiredColorScale(GetWorldSettings()->DefaultColorScale, 5.f);

// Force camera update so it doesn't sit at (0,0,0) for a full tick.
// This can have side effects with streaming.
UpdateCamera(0.f);

更新ViewTarget

UWorld 会在 Tick 函数中调用 AplayerController::UpdateCameraManager,驱动 PlayerCameraManager::UpdateCamera 更新 ViewTarget

UWorld::Tick
//...

for (int32 i = 0; i < LevelCollections.Num(); ++i)
{
    //...
    // Update cameras last. This needs to be done before NetUpdates, and after all actors have been ticked.
    for( FConstPlayerControllerIterator Iterator = GetPlayerControllerIterator(); Iterator; ++Iterator )
    {
        if (APlayerController* PlayerController = Iterator->Get())
        {
            if (!bIsPaused || PlayerController->ShouldPerformFullTickWhenPaused())
            {
                PlayerController->UpdateCameraManager(DeltaSeconds);
            }
            else if (PlayerController->PlayerCameraManager && FCameraPhotographyManager::IsSupported(this))
            {
                PlayerController->PlayerCameraManager->UpdateCameraPhotographyOnly();
            }
        }
    }
    //...
}
//...
APlayerController::UpdateCameraManager
if (PlayerCameraManager != NULL)
{
    PlayerCameraManager->UpdateCamera(DeltaSeconds);
}
APlayerCameraManager::UpdateCamera
if ((PCOwner->Player && PCOwner->IsLocalPlayerController()) || !bUseClientSideCameraUpdates || bDebugClientSideCamera)
{
    DoUpdateCamera(DeltaTime);
    //...
}

应用ViewTarget

UGameViewportClientDraw 方法渲染画面时,会通过 ULocalPlayer::CalcSceneView 方法,最终从 APlayerCameraManager 中获取 ViewTarget 中的POV数据用于渲染。

处理ViewTarget

FViewTargetAPlayerCameraManager::UpdateViewTarget 函数中进行更新。ViewTarget核心关注两个参数。

Target 相机看向的目标,后面的POV基于此进行计算。

USTRUCT(BlueprintType)  
struct FTViewTarget  
{  
    // ...
    /** Target Actor used to compute POV */  
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TViewTarget)  
    TObjectPtr<class AActor> Target;  
    // ...
};

POV 相对看向目标的各种参数。

摄像机控制

角色旋转控制

摄像机旋转控制