612 字
3 分钟

相机系统

2025-04-14
无标签
文章目录

整体流程#

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。

总体流程上:

  1. 初始化ViewTarget

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

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
}
  1. 每个 PlayerController 都会在世界创建一个 PlayerCameraManager Actor。

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

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);
  1. 更新ViewTarget

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

World Tick

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();
}
}
}
//...
}
//...

PlayerController UpdateCameraManager

APlayerController::UpdateCameraManager
if (PlayerCameraManager != NULL)
{
PlayerCameraManager->UpdateCamera(DeltaSeconds);
}

PlayerCameraManager UpdateCamera

APlayerCameraManager::UpdateCamera
if ((PCOwner->Player && PCOwner->IsLocalPlayerController()) || !bUseClientSideCameraUpdates || bDebugClientSideCamera)
{
DoUpdateCamera(DeltaTime);
//...
}
  1. 应用ViewTarget

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

处理ViewTarget#

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

  1. Target 相机看向的目标,后面的POV基于此进行计算。
USTRUCT(BlueprintType)
struct FTViewTarget
{
// ...
/** Target Actor used to compute POV */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=TViewTarget)
TObjectPtr<class AActor> Target;
// ...
};
  1. POV 相对看向目标的各种参数。

摄像机控制#

角色旋转控制#

摄像机旋转控制#