Unreal Engine 5.6 官方相机系统插件深度解析

文档版本: 1.0 | 更新日期: 2026-02-16


目录


1. 概述与架构设计

1.1 插件概述

GameplayCameras 是 Unreal Engine 5.6 引入的官方相机系统插件,旨在提供一套数据驱动高度模块化的相机解决方案。该插件取代了传统的 APlayerCameraManager 模式,采用现代化的节点图架构设计。

1.1.1 设计目标

目标 说明
数据驱动 相机行为通过资产(Asset)配置,而非硬编码
可视化编辑 支持节点图编辑器,设计师可直观调整相机逻辑
高性能 采用评估器缓存、内存池等优化技术
可扩展 支持自定义节点、服务、导演等扩展点
平滑过渡 内置强大的混合栈系统,支持复杂的相机切换

1.1.2 核心概念对照表

┌─────────────────────┬──────────────────────────────────────────────┐
│ 概念                 │ 说明                                          │
├─────────────────────┼──────────────────────────────────────────────┤
│ UCameraAsset        │ 相机资产,包含导演、过渡、参数定义              │
│ UCameraRigAsset     │ 相机装备,定义一组节点树实现特定相机行为         │
│ UCameraNode         │ 相机节点,可组合的最小功能单元                   │
│ FCameraNodeEvaluator│ 运行时评估器,执行节点的实际逻辑                 │
│ FCameraSystemEvaluator│ 相机系统评估器,管理整个评估流程              │
│ FCameraEvaluationContext│ 评估上下文,提供相机运行的环境信息           │
└─────────────────────┴──────────────────────────────────────────────┘

1.1.3 与传统相机系统的对比

// 传统方式 (APlayerCameraManager)
// - 每帧通过 PlayerCameraManager->UpdateViewTarget() 更新
// - 相机逻辑分散在各个 Actor 中
// - 难以实现复杂的混合过渡

// GameplayCameras 方式
// - 通过 UGameplayCameraComponent 运行 UCameraAsset
// - 相机逻辑集中在可复用的资产中
// - 混合栈自动处理相机切换和过渡

1.2 核心架构模式

GameplayCameras 采用 节点-评估器分离 的设计模式,这是一种类似于虚幻引擎蓝图的数据-逻辑分离架构。

1.2.1 节点与评估器分离

┌────────────────────────────────────────────────────────────────────┐
│                        架构层次图                                   │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│   ┌─────────────────────┐         ┌─────────────────────┐         │
│   │   UCameraAsset      │         │   UCameraDirector   │         │
│   │   (相机资产)         │────────▶│   (导演)            │         │
│   └─────────────────────┘         └─────────────────────┘         │
│              │                              │                      │
│              ▼                              ▼                      │
│   ┌─────────────────────┐         ┌─────────────────────┐         │
│   │  UCameraRigAsset    │         │FCameraDirectorEval  │         │
│   │  (相机装备)          │────────▶│  (导演评估器)        │         │
│   └─────────────────────┘         └─────────────────────┘         │
│              │                                                     │
│              ▼                                                     │
│   ┌─────────────────────┐         ┌─────────────────────┐         │
│   │   UCameraNode       │  Build   │FCameraNodeEvaluator │         │
│   │   (相机节点)         │────────▶│   (节点评估器)       │         │
│   │   【数据层】         │         │   【逻辑层】         │         │
│   └─────────────────────┘         └─────────────────────┘         │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

源码示例 - 节点定义 (Public/Core/CameraNode.h:38):

/**
 * The base class for a camera node.
 */
UCLASS(MinimalAPI, Abstract, DefaultToInstanced, EditInlineNew,
       meta=(CameraNodeCategories="Miscellaneous"))
class UCameraNode
    : public UObject
    , public IObjectTreeGraphObject
{
    GENERATED_BODY()

public:
    // 获取子节点列表
    UE_API FCameraNodeChildrenView GetChildren();

    // 构建评估器 - 关键方法!
    UE_API FCameraNodeEvaluatorPtr BuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const;

protected:
    // 子类重写此方法创建对应的评估器
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const
    {
        return nullptr;
    }

public:
    // 节点是否启用
    UPROPERTY(EditAnywhere, Category=Common)
    bool bIsEnabled = true;
};

源码示例 - 评估器基类 (Public/Core/CameraNodeEvaluator.h:268):

/**
 * Base class for objects responsible for running a camera node.
 */
class FCameraNodeEvaluator
{
    UE_GAMEPLAY_CAMERAS_DECLARE_RTTI_BASE(GAMEPLAYCAMERAS_API, FCameraNodeEvaluator)

public:
    // 构建子评估器
    void Build(const FCameraNodeEvaluatorBuildParams& Params);

    // 初始化评估器
    void Initialize(const FCameraNodeEvaluatorInitializeParams& Params,
                   FCameraNodeEvaluationResult& OutResult);

    // 运行评估 - 每帧调用的核心方法!
    GAMEPLAYCAMERAS_API void Run(const FCameraNodeEvaluationParams& Params,
                                  FCameraNodeEvaluationResult& OutResult);

    // 获取关联的节点数据
    const UCameraNode* GetCameraNode() const { return PrivateCameraNode; }

protected:
    // 子类实现具体的评估逻辑
    GAMEPLAYCAMERAS_API virtual void OnRun(const FCameraNodeEvaluationParams& Params,
                                            FCameraNodeEvaluationResult& OutResult) {}

private:
    // 关联的节点数据(只读)
    TObjectPtr<const UCameraNode> PrivateCameraNode;
};

1.2.2 设计优势

优势 说明
序列化友好 节点数据可保存为资产,评估器无需序列化
内存高效 评估器可复用,避免每帧创建临时对象
热重载支持 节点资产修改后可热重载,评估器自动重建
调试分离 调试信息可在评估器中收集,不影响数据层

1.2.3 实际案例:BoomArm 节点

节点定义 (Public/Nodes/Common/BoomArmCameraNode.h:17):

UCLASS(MinimalAPI, meta=(CameraNodeCategories="Common,Transform"))
class UBoomArmCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    UBoomArmCameraNode(const FObjectInitializer& ObjInit);

protected:
    // 创建对应的评估器
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const override;

public:
    // 吊臂偏移量 - 设计师可在编辑器中调整
    UPROPERTY(EditAnywhere, Category=Common)
    FVector3dCameraParameter BoomOffset;

    // 吊臂长度插值器
    UPROPERTY(EditAnywhere, Category=Common)
    TObjectPtr<UCameraValueInterpolator> BoomLengthInterpolator;

    // 输入槽 - 接收玩家输入
    UPROPERTY(meta=(ObjectTreeGraphPinDirection=Input))
    TObjectPtr<UInput2DCameraNode> InputSlot;
};

1.3 模块依赖关系图

1.3.1 整体架构图

graph TB subgraph "游戏框架层" A[UGameplayCameraComponent] B[AGameplayCameraActor] C[APlayerController] end subgraph "相机系统核心" D[FCameraSystemEvaluator] E[FCameraEvaluationContext] F[FCameraEvaluationContextStack] end subgraph "资产层" G[UCameraAsset] H[UCameraRigAsset] I[UCameraDirector] end subgraph "评估层" J[FRootCameraNodeEvaluator] K[FBlendStackCameraNodeEvaluator] L[FCameraNodeEvaluator] end subgraph "节点层" M[URootCameraNode] N[UBlendCameraNode] O[UCameraNode] end subgraph "服务层" P[FCameraEvaluationService] Q[FCameraShakeService] R[FCameraModifierService] end A --> D B --> A C --> A D --> E D --> F D --> J E --> I G --> I G --> H H --> M J --> K K --> L M --> N N --> O D --> P P --> Q P --> R

1.3.2 评估流程图

sequenceDiagram participant Game as 游戏框架 participant CSE as FCameraSystemEvaluator participant EC as FCameraEvaluationContext participant DE as FCameraDirectorEvaluator participant Root as FRootCameraNodeEvaluator participant BS as FBlendStackEvaluator participant Node as FCameraNodeEvaluator Game->>CSE: Update(DeltaTime) CSE->>CSE: PreUpdateServices() CSE->>EC: GetActiveContext() EC-->>CSE: ActiveContext CSE->>DE: Run() DE-->>CSE: ActivationRequests CSE->>Root: ExecuteCameraDirectorRequest() CSE->>Root: Run(Params, Result) Root->>BS: Run(Params, Result) [Base] Root->>BS: Run(Params, Result) [Main] BS->>Node: Run(Params, Result) Node-->>BS: Result BS-->>Root: BlendedResult Root-->>CSE: FinalResult CSE->>CSE: PostUpdateServices() CSE-->>Game: GetEvaluatedCameraView()

1.3.3 层系统架构

graph LR subgraph "四层架构" Base[Base Layer<br/>基础层<br/>持久化/叠加] Main[Main Layer<br/>主层<br/>瞬态/混合] Global[Global Layer<br/>全局层<br/>持久化/叠加] Visual[Visual Layer<br/>视觉层<br/>后处理效果] end Base --> Main Main --> Global Global --> Visual style Base fill:#e1f5fe style Main fill:#fff3e0 style Global fill:#e8f5e9 style Visual fill:#fce4ec

1.4 目录结构说明

1.4.1 源码目录组织

GameplayCameras/Source/GameplayCameras/
│
├── Public/                          # 公共头文件
│   │
│   ├── Core/                        # 核心系统 (72个文件)
│   │   ├── CameraSystemEvaluator.h  # 相机系统评估器
│   │   ├── CameraNodeEvaluator.h    # 节点评估器基类
│   │   ├── CameraNode.h             # 节点基类
│   │   ├── CameraPose.h             # 相机姿态
│   │   ├── CameraVariableTable.h    # 变量表
│   │   ├── CameraRigAsset.h         # 相机装备资产
│   │   ├── CameraAsset.h            # 相机资产
│   │   ├── BlendCameraNode.h        # 混合节点基类
│   │   ├── BlendStackCameraNode.h   # 混合栈节点
│   │   ├── RootCameraNode.h         # 根节点
│   │   └── DefaultRootCameraNode.h  # 默认根节点实现
│   │
│   ├── Nodes/                       # 节点实现
│   │   ├── Common/                  # 通用节点 (21个)
│   │   │   ├── BoomArmCameraNode.h
│   │   │   ├── ArrayCameraNode.h
│   │   │   └── ...
│   │   ├── Blends/                  # 混合节点 (8个)
│   │   ├── Attach/                  # 附加节点 (4个)
│   │   ├── Framing/                 # 构图节点 (5个)
│   │   ├── Input/                   # 输入节点 (6个)
│   │   ├── Shakes/                  # 震动节点 (6个)
│   │   └── Collision/               # 碰撞节点 (2个)
│   │
│   ├── Services/                    # 评估服务 (4个)
│   │   ├── CameraModifierService.h
│   │   ├── CameraShakeService.h
│   │   └── ...
│   │
│   ├── Directors/                   # 导演系统 (6个)
│   │   ├── BlueprintCameraDirector.h
│   │   ├── SingleCameraDirector.h
│   │   └── ...
│   │
│   ├── GameFramework/               # 游戏框架集成 (19个)
│   │   ├── GameplayCameraComponent.h
│   │   ├── GameplayCameraActor.h
│   │   └── ...
│   │
│   ├── Debug/                       # 调试系统 (24个)
│   │   └── ...
│   │
│   └── Build/                       # 构建系统
│       └── ...
│
└── Private/                         # 私有实现文件
    └── [与 Public 对应的目录结构]

1.4.2 关键目录说明

目录 职责 关键文件
Core/ 核心类型定义和基类 CameraSystemEvaluator.h, CameraNodeEvaluator.h
Nodes/ 可组合的相机功能节点 BoomArmCameraNode.h, SmoothBlendCameraNode.h
Services/ 横切关注点的服务实现 CameraShakeService.h, CameraModifierService.h
Directors/ 控制相机装备激活的导演 SingleCameraDirector.h, BlueprintCameraDirector.h
GameFramework/ 与 UE 游戏框架的集成 GameplayCameraComponent.h
Debug/ 调试可视化和诊断工具 CameraDebugBlock.h

1.4.3 命名约定

// 节点类命名:U + 功能描述 + CameraNode
UCLASS()
class UBoomArmCameraNode : public UCameraNode { ... };

// 评估器类命名:F + 功能描述 + CameraNodeEvaluator
class FBoomArmCameraNodeEvaluator : public FCameraNodeEvaluator { ... };

// 资产类命名:U + 功能描述 + Asset
UCLASS()
class UCameraRigAsset : public UBaseCameraObject { ... };

// 服务类命名:F + 功能描述 + Service
class FCameraShakeService : public FCameraEvaluationService { ... };

2. 核心类与继承体系

2.1 评估器体系 (FCameraNodeEvaluator 家族)

评估器是 GameplayCameras 的运行时逻辑层,负责执行实际的相机计算。所有评估器都继承自 FCameraNodeEvaluator 基类。

2.1.1 自定义 RTTI 系统

评估器系统使用自定义的运行时类型识别(RTTI)机制,而非虚幻引擎原生的 UObject 反射系统。这样做的原因是评估器不是 UObject,需要轻量级的类型识别。

源码位置: Public/Core/CameraObjectRtti.h

// 类型ID结构
struct FCameraObjectTypeID
{
    uint32 ID;

    bool IsValid() const { return ID != MAX_uint32; }
    static FCameraObjectTypeID Invalid() { return FCameraObjectTypeID(MAX_uint32); }
};

// 类型信息结构
struct FCameraObjectTypeInfo
{
    FName TypeName;
    uint32 Sizeof = 0;
    uint32 Alignof = 0;
    using FConstructor = void(*)(void*);
    FConstructor Constructor;
    using FDestructor = void(*)(void*);
    FDestructor Destructor;
};

RTTI 宏系统:

// 在基类中声明 RTTI(根类)
#define UE_GAMEPLAY_CAMERAS_DECLARE_RTTI_BASE(ApiDeclSpec, ClassName)\
public:\
    static const TCameraObjectTypeID<ClassName>& StaticTypeID();\
    virtual const FCameraObjectTypeID& GetTypeID() const;\
    virtual bool IsKindOf(const FCameraObjectTypeID& InTypeID) const;\
    template<typename Type> Type* CastThis();\
    template<typename Type> Type* CastThisChecked();

// 在派生类中声明 RTTI
#define UE_GAMEPLAY_CAMERAS_DECLARE_RTTI(ApiDeclSpec, ClassName, BaseClassName)\
public:\
    using Super = BaseClassName;\
    static const TCameraObjectTypeID<ClassName>& StaticTypeID();\
    virtual const FCameraObjectTypeID& GetTypeID() const override;\
    virtual bool IsKindOf(const FCameraObjectTypeID& InTypeID) const override;

// 在 cpp 文件中定义 RTTI
#define UE_GAMEPLAY_CAMERAS_DEFINE_RTTI(ClassName)\
    const TCameraObjectTypeID<ClassName> ClassName::PrivateTypeID = \
        TCameraObjectTypeID<ClassName>::RegisterType(#ClassName);

实际使用示例:

// 声明评估器
class FBoomArmCameraNodeEvaluator : public FCameraNodeEvaluator
{
    UE_DECLARE_CAMERA_NODE_EVALUATOR(GAMEPLAYCAMERAS_API, FBoomArmCameraNodeEvaluator)
    // ...
};

// 在 cpp 中定义
UE_DEFINE_CAMERA_NODE_EVALUATOR(FBoomArmCameraNodeEvaluator)

// 类型检查和转换
if (FBoomArmCameraNodeEvaluator* BoomEval = Evaluator->CastThis<FBoomArmCameraNodeEvaluator>())
{
    // 安全地访问特定类型的方法
}

2.1.2 评估器继承层次

classDiagram class FCameraNodeEvaluator { <<abstract>> +FCameraObjectTypeID TypeID +TObjectPtr~UCameraNode~ PrivateCameraNode +ECameraNodeEvaluatorFlags PrivateFlags +Build(Params) +Initialize(Params, OutResult) +Run(Params, OutResult) +GetCameraNode() const UCameraNode* #OnRun(Params, OutResult)* } class FRootCameraNodeEvaluator { <<abstract>> +FCameraSystemEvaluator* OwningEvaluator +ActivateCameraRig(Params) FCameraRigInstanceID +DeactivateCameraRig(Params) +GetActiveCameraRigInfo(OutInfo) #OnActivateCameraRig(Params)* #OnDeactivateCameraRig(Params)* } class FDefaultRootCameraNodeEvaluator { -FPersistentBlendStackCameraNodeEvaluator* BaseLayer -FTransientBlendStackCameraNodeEvaluator* MainLayer -FPersistentBlendStackCameraNodeEvaluator* GlobalLayer -FPersistentBlendStackCameraNodeEvaluator* VisualLayer +OnRun(Params, OutResult) } class FBlendStackCameraNodeEvaluator { <<abstract>> #TArray~FCameraRigEntry~ Entries #FCameraSystemEvaluator* OwningEvaluator +GetActiveCameraRigEvaluationInfo() +HasAnyRunningCameraRig(Context) } class FTransientBlendStackCameraNodeEvaluator { -TArray~FCameraRigEntryExtraInfo~ EntryExtraInfos -FCameraVariableTable PreBlendVariableTable +Push(Params) FBlendStackEntryID +Freeze(Params) +FreezeAll(Context) } class FPersistentBlendStackCameraNodeEvaluator { -TArray~FCameraRigEntryExtraInfo~ EntryExtraInfos +Insert(Params) FBlendStackEntryID +Remove(Params) +RemoveAll(Context, bImmediately) } class FBlendCameraNodeEvaluator { <<abstract>> +BlendParameters(Params, OutResult) +BlendResults(Params, OutResult) #OnBlendParameters(Params, OutResult)* #OnBlendResults(Params, OutResult)* } class FSmoothBlendCameraNodeEvaluator { -float ElapsedTime -float TotalDuration -ESmoothCameraBlendType BlendType +OnBlendResults(Params, OutResult) } FCameraNodeEvaluator <|-- FRootCameraNodeEvaluator FCameraNodeEvaluator <|-- FBlendStackCameraNodeEvaluator FCameraNodeEvaluator <|-- FBlendCameraNodeEvaluator FRootCameraNodeEvaluator <|-- FDefaultRootCameraNodeEvaluator FBlendStackCameraNodeEvaluator <|-- FTransientBlendStackCameraNodeEvaluator FBlendStackCameraNodeEvaluator <|-- FPersistentBlendStackCameraNodeEvaluator FBlendCameraNodeEvaluator <|-- FSmoothBlendCameraNodeEvaluator

2.1.3 评估器核心方法生命周期

// 评估器的生命周期
class FCameraNodeEvaluator
{
public:
    // 1. 构建阶段 - 创建子评估器树
    void Build(const FCameraNodeEvaluatorBuildParams& Params);

    // 2. 初始化阶段 - 设置初始状态
    void Initialize(const FCameraNodeEvaluatorInitializeParams& Params,
                    FCameraNodeEvaluationResult& OutResult);

    // 3. 每帧评估 - 核心逻辑
    void Run(const FCameraNodeEvaluationParams& Params,
             FCameraNodeEvaluationResult& OutResult);

    // 4. 序列化 - 保存/恢复状态
    void Serialize(const FCameraNodeEvaluatorSerializeParams& Params, FArchive& Ar);
};

2.1.4 评估器标志

// 源码位置: Public/Core/CameraNodeEvaluator.h:37
enum class ECameraNodeEvaluatorFlags
{
    None = 0,
    // 需要参数更新回调
    NeedsParameterUpdate = 1 << 0,
    // 需要序列化
    NeedsSerialize = 1 << 1,
    // 支持操作(如 IK)
    SupportsOperations = 1 << 2,

    // 默认标志
    Default = NeedsParameterUpdate | NeedsSerialize | SupportsOperations
};

2.2 节点体系 (UCameraNode 家族)

节点是 GameplayCameras 的数据层,定义相机行为的数据结构和编辑器可见属性。

2.2.1 节点基类

源码位置: Public/Core/CameraNode.h:38

UCLASS(MinimalAPI, Abstract, DefaultToInstanced, EditInlineNew,
       meta=(CameraNodeCategories="Miscellaneous"))
class UCameraNode : public UObject, public IObjectTreeGraphObject
{
    GENERATED_BODY()

public:
    using FCameraBuildLog = UE::Cameras::FCameraBuildLog;
    using FCameraNodeEvaluatorBuilder = UE::Cameras::FCameraNodeEvaluatorBuilder;

    // 获取子节点视图
    UE_API FCameraNodeChildrenView GetChildren();

    // 构建前预处理
    UE_API void PreBuild(FCameraBuildLog& BuildLog);

    // 构建分配信息
    UE_API void Build(FCameraObjectBuildContext& BuildContext);

    // 构建评估器 - 关键方法!
    UE_API FCameraNodeEvaluatorPtr BuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const;

protected:
    // 子类重写:返回子节点
    virtual FCameraNodeChildrenView OnGetChildren() { return FCameraNodeChildrenView(); }

    // 子类重写:预处理逻辑
    virtual void OnPreBuild(FCameraBuildLog& BuildLog) {}

    // 子类重写:构建逻辑
    virtual void OnBuild(FCameraObjectBuildContext& BuildContext) {}

    // 子类重写:创建对应的评估器
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const
    {
        return nullptr;
    }

public:
    // 节点启用状态
    UPROPERTY(EditAnywhere, Category=Common)
    bool bIsEnabled = true;

#if WITH_EDITORONLY_DATA
    // 编辑器中的节点位置
    UPROPERTY()
    FIntVector2 GraphNodePos = FIntVector2::ZeroValue;

    // 节点注释
    UPROPERTY()
    FString GraphNodeComment;
#endif
};

2.2.2 节点继承层次

classDiagram class UCameraNode { <<abstract>> +bool bIsEnabled +GetChildren() FCameraNodeChildrenView +BuildEvaluator(Builder)* #OnGetChildren()* #OnBuildEvaluator(Builder)* } class URootCameraNode { <<abstract>> } class UDefaultRootCameraNode { +UBlendStackCameraNode* BaseLayer +UBlendStackCameraNode* MainLayer +UBlendStackCameraNode* GlobalLayer +UBlendStackCameraNode* VisualLayer } class UBlendCameraNode { <<abstract>> } class USmoothBlendCameraNode { +ESmoothCameraBlendType BlendType } class ULinearBlendCameraNode { +FFloatCameraParameter Duration } class UBlendStackCameraNode { +ECameraBlendStackType BlendStackType +ECameraRigLayer Layer } class UArrayCameraNode { +TArray~UCameraNode*~ Children } class UBoomArmCameraNode { +FVector3dCameraParameter BoomOffset +UCameraValueInterpolator* BoomLengthInterpolator +UInput2DCameraNode* InputSlot } class UAttachToPlayerPawnCameraNode { +FBoneSocketCameraAttachment TargetAttachment +bool bApplyPlayerControlRotation } class UInput2DCameraNode { +FFloatCameraParameter YawSpeed +FFloatCameraParameter PitchSpeed } UCameraNode <|-- URootCameraNode UCameraNode <|-- UBlendCameraNode UCameraNode <|-- UBlendStackCameraNode UCameraNode <|-- UArrayCameraNode UCameraNode <|-- UBoomArmCameraNode UCameraNode <|-- UAttachToPlayerPawnCameraNode UCameraNode <|-- UInput2DCameraNode URootCameraNode <|-- UDefaultRootCameraNode UBlendCameraNode <|-- USmoothBlendCameraNode UBlendCameraNode <|-- ULinearBlendCameraNode

2.2.3 节点分类(CameraNodeCategories)

节点通过 meta=(CameraNodeCategories="...") 指定在编辑器中显示的分类:

分类 说明 示例节点
Common 通用节点 UArrayCameraNode, UBoomArmCameraNode
Common,Transform 变换相关 UOffsetCameraNode, USetLocationCameraNode
Blends 混合节点 USmoothBlendCameraNode, ULinearBlendCameraNode
Input 输入处理 UInput2DCameraNode, UInput1DCameraNode
Attach 附加功能 UAttachToActorCameraNode, UAttachToPlayerPawnCameraNode
Framing 构图功能 UDollyFramingCameraNode, UPanningFramingCameraNode
Shakes 震动效果 UEnvelopeShakeCameraNode, UPerlinNoiseRotationShakeCameraNode
Collision 碰撞处理 UCollisionPushCameraNode

2.2.4 实际案例:Sequence 节点

UArrayCameraNode(编辑器显示名为 "Sequence")是一个组合节点,按顺序执行多个子节点:

// 源码位置: Public/Nodes/Common/ArrayCameraNode.h:14
UCLASS(MinimalAPI, meta=(DisplayName="Sequence", CameraNodeCategories="Common,Utility"))
class UArrayCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    UArrayCameraNode(const FObjectInitializer& ObjInit);

protected:
    // 返回子节点列表
    virtual FCameraNodeChildrenView OnGetChildren() override;

    // 创建评估器
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const override;

public:
    // 子节点数组 - 设计师在编辑器中配置
    UPROPERTY()
    TArray<TObjectPtr<UCameraNode>> Children;
};

使用场景示例:

Sequence 节点结构:
┌─────────────────────────────────────┐
│         Sequence (ArrayNode)        │
├─────────────────────────────────────┤
│  [0] AttachToPlayerPawn             │  ← 附加到玩家
│  [1] BoomArm                        │  ← 吊臂控制
│  [2] CollisionPush                  │  ← 碰撞推挤
│  [3] DampenRotation                 │  ← 旋转阻尼
└─────────────────────────────────────┘

2.3 资产体系

资产是 GameplayCameras 的可复用配置单元,存储在内容浏览器中。

2.3.1 资产继承关系

classDiagram class UObject { <<UObject>> } class UBaseCameraObject { <<abstract>> +UCameraNode* RootNode +GetRootNode() UCameraNode* } class UCameraRigAsset { +UCameraNode* RootNode +FGameplayTagContainer GameplayTags +TArray~UCameraRigTransition*~ EnterTransitions +TArray~UCameraRigTransition*~ ExitTransitions +ECameraRigInitialOrientation InitialOrientation +FGuid Guid +BuildCameraRig() } class UCameraAsset { +UCameraDirector* CameraDirector +TArray~UCameraRigTransition*~ EnterTransitions +TArray~UCameraRigTransition*~ ExitTransitions +FInstancedPropertyBag DefaultParameters +TArray~FCameraObjectInterfaceParameterDefinition~ ParameterDefinitions +BuildCamera() } class UCameraDirector { <<abstract>> +FCameraRigProxyRedirectTable CameraRigProxyRedirectTable +BuildEvaluator(Builder)* +BuildCameraDirector(BuildLog) } class USingleCameraDirector { +FCameraRigProxy CameraRigProxy } class UBlueprintCameraDirector { +UBlueprintGeneratedClass* GeneratedClass } UObject <|-- UBaseCameraObject UObject <|-- UCameraAsset UObject <|-- UCameraDirector UBaseCameraObject <|-- UCameraRigAsset UCameraDirector <|-- USingleCameraDirector UCameraDirector <|-- UBlueprintCameraDirector

2.3.2 UCameraAsset 相机资产

源码位置: Public/Core/CameraAsset.h:69

UCameraAsset 是顶级相机配置容器,包含:

UCLASS(MinimalAPI)
class UCameraAsset : public UObject
                    , public IHasCameraBuildStatus
                    , public IObjectTreeGraphObject
                    , public IObjectTreeGraphRootObject
{
    GENERATED_BODY()

public:
    // 获取/设置导演
    UCameraDirector* GetCameraDirector() const { return CameraDirector; }
    void SetCameraDirector(UCameraDirector* InCameraDirector);

    // 进入/退出过渡
    TArrayView<const TObjectPtr<UCameraRigTransition>> GetEnterTransitions() const;
    void AddEnterTransition(UCameraRigTransition* InTransition);
    TArrayView<const TObjectPtr<UCameraRigTransition>> GetExitTransitions() const;
    void AddExitTransition(UCameraRigTransition* InTransition);

    // 默认参数
    const FInstancedPropertyBag& GetDefaultParameters() const { return DefaultParameters; }
    FInstancedPropertyBag& GetDefaultParameters() { return DefaultParameters; }

    // 参数定义
    TConstArrayView<FCameraObjectInterfaceParameterDefinition> GetParameterDefinitions() const;

    // 构建相机
    void BuildCamera();
    void BuildCamera(UE::Cameras::FCameraBuildLog& InBuildLog);

private:
    // 导演实例
    UPROPERTY(Instanced)
    TObjectPtr<UCameraDirector> CameraDirector;

    // 进入过渡列表
    UPROPERTY(Instanced)
    TArray<TObjectPtr<UCameraRigTransition>> EnterTransitions;

    // 退出过渡列表
    UPROPERTY(Instanced)
    TArray<TObjectPtr<UCameraRigTransition>> ExitTransitions;

    // 构建状态
    UPROPERTY(Transient)
    ECameraBuildStatus BuildStatus = ECameraBuildStatus::Dirty;

    // 默认参数值
    UPROPERTY()
    FInstancedPropertyBag DefaultParameters;

    // 参数定义列表
    UPROPERTY()
    TArray<FCameraObjectInterfaceParameterDefinition> ParameterDefinitions;
};

2.3.3 UCameraRigAsset 相机装备资产

源码位置: Public/Core/CameraRigAsset.h:57

UCameraRigAsset 定义一组可复用的相机行为:

UCLASS(MinimalAPI)
class UCameraRigAsset : public UBaseCameraObject
                       , public IGameplayTagAssetInterface
                       , public IHasCameraBuildStatus
                       , public IObjectTreeGraphObject
                       , public IObjectTreeGraphRootObject
{
    GENERATED_BODY()

public:
    // 根节点 - 装备的入口点
    UPROPERTY(Instanced)
    TObjectPtr<UCameraNode> RootNode;

    // Gameplay 标签
    UPROPERTY(EditAnywhere, Category=GameplayTags)
    FGameplayTagContainer GameplayTags;

    // 进入过渡
    UPROPERTY(Instanced)
    TArray<TObjectPtr<UCameraRigTransition>> EnterTransitions;

    // 退出过渡
    UPROPERTY(Instanced)
    TArray<TObjectPtr<UCameraRigTransition>> ExitTransitions;

    // 初始朝向模式
    UPROPERTY(EditAnywhere, Category="Transition")
    ECameraRigInitialOrientation InitialOrientation = ECameraRigInitialOrientation::None;

    // 唯一标识符
    const FGuid& GetGuid() const { return Guid; }

    // 构建装备
    void BuildCameraRig();
    void BuildCameraRig(UE::Cameras::FCameraBuildLog& InBuildLog);

private:
    UPROPERTY()
    FGuid Guid;
};

2.3.4 资产与运行时的关系

┌─────────────────────────────────────────────────────────────────────┐
│                        资产层次 (编辑时)                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   UCameraAsset                                                      │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  UCameraDirector (SingleCameraDirector)                     │   │
│   │  └── FCameraRigProxy → UCameraRigAsset                      │   │
│   │      └── UCameraNode (RootNode)                             │   │
│   │          └── UArrayCameraNode                               │   │
│   │              ├── UAttachToPlayerPawnCameraNode              │   │
│   │              ├── UBoomArmCameraNode                         │   │
│   │              └── UCollisionPushCameraNode                   │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
                              │
                              │ Build
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                      评估器层次 (运行时)                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   FCameraSystemEvaluator                                            │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  FCameraDirectorEvaluator                                    │   │
│   │  └── FRootCameraNodeEvaluator (DefaultRoot)                 │   │
│   │      ├── FPersistentBlendStackEvaluator (BaseLayer)         │   │
│   │      ├── FTransientBlendStackEvaluator (MainLayer)          │   │
│   │      │   └── FCameraRigEntry                                 │   │
│   │      │       └── FArrayCameraNodeEvaluator                   │   │
│   │      │           ├── FAttachToPlayerPawnEvaluator           │   │
│   │      │           ├── FBoomArmEvaluator                       │   │
│   │      │           └── FCollisionPushEvaluator                 │   │
│   │      ├── FPersistentBlendStackEvaluator (GlobalLayer)       │   │
│   │      └── FPersistentBlendStackEvaluator (VisualLayer)       │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.4 类图与关系说明

2.4.1 完整的核心类关系图

graph TB subgraph "资产层 (UObject)" CA[UCameraAsset] CR[UCameraRigAsset] CD[UCameraDirector] CN[UCameraNode] CT[UCameraRigTransition] end subgraph "评估器层 (C++)" CSE[FCameraSystemEvaluator] CEC[FCameraEvaluationContext] CDE[FCameraDirectorEvaluator] RNE[FRootCameraNodeEvaluator] BSE[FBlendStackEvaluator] NE[FCameraNodeEvaluator] end subgraph "数据结构" CP[FCameraPose] VT[FCameraVariableTable] CDT[FCameraContextDataTable] ER[FCameraNodeEvaluationResult] end subgraph "服务层" ES[FCameraEvaluationService] SS[FCameraShakeService] MS[FCameraModifierService] end CA --> CD CA --> CT CD --> CDE CR --> CN CN --> NE CSE --> CEC CSE --> RNE CEC --> CDE RNE --> BSE BSE --> NE NE --> ER ER --> CP ER --> VT ER --> CDT CSE --> ES ES --> SS ES --> MS

2.4.2 核心类职责表

类名 类型 职责 生命周期
UCameraAsset UObject 顶层相机配置容器 持久化资产
UCameraRigAsset UObject 可复用的相机行为定义 持久化资产
UCameraNode UObject 节点数据定义 持久化资产
FCameraSystemEvaluator C++ 管理整个评估流程 游戏运行时
FCameraEvaluationContext C++ 提供评估的环境和上下文 游戏运行时
FCameraNodeEvaluator C++ 执行节点评估逻辑 游戏运行时
FCameraPose C++ 相机姿态数据 每帧更新
FCameraVariableTable C++ 参数变量存储 每帧更新
FCameraNodeEvaluationResult C++ 评估结果容器 每帧更新

3. 求值流程详解

3.1 入口点与调用链

3.1.1 从游戏框架到相机系统

GameplayCameras 通过 UGameplayCameraComponent 与游戏框架集成。整个调用链如下:

APlayerController::GetPlayerViewPoint()
    └── APlayerCameraManager::CalcCameraView()
        └── UGameplayCameraComponentBase::GetCameraView()
            └── FCameraSystemEvaluator::Update()
                └── FRootCameraNodeEvaluator::Run()
                    └── [四层评估]

源码位置: Private/Core/CameraSystemEvaluator.cpp:225

void FCameraSystemEvaluator::Update(const FCameraSystemEvaluationParams& Params)
{
    // 委托给内部实现,使用标准评估类型
    UpdateImpl(Params.DeltaTime, ECameraNodeEvaluationType::Standard);
}

3.1.2 核心更新实现

源码位置: Private/Core/CameraSystemEvaluator.cpp:230

void FCameraSystemEvaluator::UpdateImpl(float DeltaTime, ECameraNodeEvaluationType EvaluationType)
{
    SCOPE_CYCLE_COUNTER(CameraSystemEval_Total);  // 性能统计

    // Step 1: 重置结果标志
    RootNodeResult.ResetFrameFlags();

    // Step 2: 重置变量和上下文数据
    RootNodeResult.VariableTable.AutoResetValues();
    RootNodeResult.ContextDataTable.AutoResetValues();

    // Step 3: 预更新所有服务
    PreUpdateServices(DeltaTime, ECameraEvaluationServiceFlags::None);

    // Step 4: 获取活动评估上下文
    TSharedPtr<FCameraEvaluationContext> ActiveContext = ContextStack.GetActiveContext();
    if (UNLIKELY(!ActiveContext.IsValid()))
    {
        Result.bIsValid = false;
        PreVisualResult.bIsValid = false;
        return;
    }

    // Step 5: 运行相机导演
    FCameraDirectorEvaluator* ActiveDirectorEvaluator = ActiveContext->GetDirectorEvaluator();
    if (ActiveDirectorEvaluator)
    {
        UpdateCameraDirector(DeltaTime, ActiveDirectorEvaluator);
    }

    // Step 6: 运行节点树评估
    {
        FCameraNodeEvaluationParams NodeParams;
        NodeParams.Evaluator = this;
        NodeParams.DeltaTime = DeltaTime;
        NodeParams.EvaluationType = EvaluationType;

        RootNodeResult.Reset();
        RootEvaluator->Run(NodeParams, RootNodeResult);
        RootNodeResult.bIsValid = true;
    }

    // Step 7: 后更新所有服务
    PostUpdateServices(DeltaTime, ECameraEvaluationServiceFlags::None);

    // Step 8: 收集最终结果
    PreVisualResult.Reset(RootEvaluator->GetPreVisualLayerResult());
    Result.Reset(RootNodeResult);

    // Step 9: 生成调试信息(如果启用)
#if UE_GAMEPLAY_CAMERAS_DEBUG
    BuildDebugBlocksIfNeeded();
#endif

    // Step 10: 结束更新
    ContextStack.OnEndCameraSystemUpdate();
}

3.2 每帧更新流程

3.2.1 更新流程图

flowchart TD Start([开始 Update]) --> Reset[重置帧标志和数据] Reset --> PreSvc[PreUpdateServices<br/>预更新服务] PreSvc --> GetCtx{获取活动上下文} GetCtx -->|无效| Invalid[返回无效结果] GetCtx -->|有效| RunDir[运行相机导演<br/>处理激活/停用请求] RunDir --> RunTree[运行节点树<br/>RootEvaluator->Run] RunTree --> PostSvc[PostUpdateServices<br/>后更新服务] PostSvc --> Harvest[收集结果<br/>PreVisualResult / Result] Harvest --> Debug{调试启用?} Debug -->|是| BuildDebug[构建调试块] Debug -->|否| EndCtx[结束更新通知] BuildDebug --> EndCtx EndCtx --> End([结束]) Invalid --> End

3.2.2 评估类型

源码位置: Public/Core/CameraNodeEvaluator.h:132

enum class ECameraNodeEvaluationType
{
    /** 正常评估 */
    Standard,
    /** 视角旋转预览评估 */
    ViewRotationPreview,
    /** IK 目标评估 */
    IK,

#if WITH_EDITOR
    /** 编辑器预览评估 */
    EditorPreview
#endif
};

3.2.3 服务更新周期

源码位置: Private/Core/CameraSystemEvaluator.cpp:415

void FCameraSystemEvaluator::PreUpdateServices(float DeltaTime, ECameraEvaluationServiceFlags ExtraFlags)
{
    FCameraEvaluationServiceUpdateParams ServiceUpdateParams;
    ServiceUpdateParams.Evaluator = this;
    ServiceUpdateParams.DeltaTime = DeltaTime;

    FCameraEvaluationServiceUpdateResult ServiceUpdateResult(RootNodeResult);

    for (TSharedPtr<FCameraEvaluationService> EvaluationService : EvaluationServices)
    {
        if (EvaluationService->HasAllEvaluationServiceFlags(
            ECameraEvaluationServiceFlags::NeedsPreUpdate | ExtraFlags))
        {
            EvaluationService->PreUpdate(ServiceUpdateParams, ServiceUpdateResult);
        }
    }
}

3.3 混合栈求值过程

3.3.1 四层评估流程

源码位置: Private/Core/DefaultRootCameraNode.cpp:77

void FDefaultRootCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    // 1. Base Layer - 基础层(持久化、叠加)
    BaseLayer->Run(Params, OutResult);

    // 2. Main Layer - 主层(瞬态、混合)
    MainLayer->Run(Params, OutResult);

    // 3. Global Layer - 全局层(持久化、叠加)
    GlobalLayer->Run(Params, OutResult);

    // 保存 Pre-Visual 结果(用于某些特殊用途)
    SetPreVisualLayerResult(OutResult);

    // 4. Visual Layer - 视觉层(后处理效果)
    // 注意:IK 和视角预览评估不运行视觉层
    if (Params.EvaluationType != ECameraNodeEvaluationType::IK &&
        Params.EvaluationType != ECameraNodeEvaluationType::ViewRotationPreview)
    {
        VisualLayer->Run(Params, OutResult);
    }
}

3.3.2 瞬态混合栈求值 (Main Layer)

源码位置: Private/Core/TransientBlendStackCameraNode.cpp:209

void FTransientBlendStackCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    ensure(Entries.Num() == EntryExtraInfos.Num());

    // Step 1: 验证条目并解析评估上下文
    TArray<FResolvedEntry> ResolvedEntries;
    ResolveEntries(ResolvedEntries);

    // Step 2: 预混合准备 - 收集参数
    InternalPreBlendPrepare(ResolvedEntries, Params, OutResult);

    // Step 3: 预混合执行 - 混合输入变量
    InternalPreBlendExecute(ResolvedEntries, Params, OutResult);

    // Step 4: 更新 - 运行每个条目的根节点
    InternalUpdate(ResolvedEntries, Params, OutResult);

    // Step 5: 后混合执行 - 混合结果并弹出已完成条目
    InternalPostBlendExecute(ResolvedEntries, Params, OutResult);

    // Step 6: 清理
    OnRunFinished(OutResult);
    InternalRunFinished(OutResult);
}

3.3.3 混合栈求值详解

Step 1: 预混合准备 (InternalPreBlendPrepare)

void FTransientBlendStackCameraNodeEvaluator::InternalPreBlendPrepare(
    TArrayView<FResolvedEntry> ResolvedEntries,
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    for (FResolvedEntry& ResolvedEntry : ResolvedEntries)
    {
        FCameraRigEntry& Entry = ResolvedEntry.Entry;

        if (UNLIKELY(Entry.Flags.bIsFrozen))
            continue;  // 冻结条目跳过

        // 复制输入变量到条目结果
        CurResult.VariableTable.OverrideAll(OutResult.VariableTable);

        // 应用上下文覆盖
        CurResult.VariableTable.OverrideAll(ContextResult.VariableTable, true);

        // 应用参数设置器服务
        if (ParameterSetterService)
        {
            ParameterSetterService->ApplyCameraVariableSetters(CurResult.VariableTable);
        }

        // 收集需要参数更新的节点
        if (!EntryExtraInfo.bInputRunThisFrame)
        {
            FCameraBlendedParameterUpdateParams InputParams(CurParams, CurResult.CameraPose);
            FCameraBlendedParameterUpdateResult InputResult(CurResult.VariableTable);

            Entry.EvaluatorHierarchy.ForEachEvaluator(
                ECameraNodeEvaluatorFlags::NeedsParameterUpdate,
                [&InputParams, &InputResult](FCameraNodeEvaluator* ParameterEvaluator)
                {
                    ParameterEvaluator->UpdateParameters(InputParams, InputResult);
                });
        }

        // 运行混合节点的 Run
        FBlendCameraNodeEvaluator* EntryBlendEvaluator = Entry.RootEvaluator->GetBlendEvaluator();
        if (EntryBlendEvaluator)
        {
            EntryBlendEvaluator->Run(CurParams, CurResult);
        }
    }
}

Step 2: 预混合执行 (InternalPreBlendExecute)

void FTransientBlendStackCameraNodeEvaluator::InternalPreBlendExecute(
    TArrayView<FResolvedEntry> ResolvedEntries,
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    PreBlendVariableTable.ClearAllWrittenThisFrameFlags();

    // 混合所有条目的输入变量
    constexpr ECameraVariableTableFilter VariableTableFilter = ECameraVariableTableFilter::InputOnly;

    for (FResolvedEntry& ResolvedEntry : ResolvedEntries)
    {
        FCameraRigEntry& Entry = ResolvedEntry.Entry;

        if (!Entry.Flags.bIsFrozen)
        {
            // 调用混合节点的 BlendParameters
            FBlendCameraNodeEvaluator* EntryBlendEvaluator = Entry.RootEvaluator->GetBlendEvaluator();
            if (EntryBlendEvaluator)
            {
                FCameraNodePreBlendParams PreBlendParams(CurParams, CurResult.CameraPose, CurResult.VariableTable);
                FCameraNodePreBlendResult PreBlendResult(PreBlendVariableTable);
                EntryBlendEvaluator->BlendParameters(PreBlendParams, PreBlendResult);
            }
        }
        else
        {
            // 冻结条目使用最后评估的值
            PreBlendVariableTable.Override(CurResult.VariableTable, VariableTableFilter);
        }
    }

    // 将预混合值写回每个条目
    for (FResolvedEntry& ResolvedEntry : ResolvedEntries)
    {
        FCameraRigEntry& Entry = ResolvedEntry.Entry;
        if (!Entry.Flags.bIsFrozen)
        {
            CurResult.VariableTable.Override(PreBlendVariableTable, ECameraVariableTableFilter::KnownOnly);
        }
    }
}

Step 3: 更新 (InternalUpdate)

void FTransientBlendStackCameraNodeEvaluator::InternalUpdate(
    TArrayView<FResolvedEntry> ResolvedEntries,
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    for (FResolvedEntry& ResolvedEntry : ResolvedEntries)
    {
        FCameraRigEntry& Entry = ResolvedEntry.Entry;

        if (UNLIKELY(Entry.Flags.bIsFrozen))
            continue;  // 冻结条目跳过

        FCameraNodeEvaluationResult& CurResult = Entry.Result;

        // 重置结果并设置初始状态
        CurResult.Reset();
        CurResult.CameraPose = OutResult.CameraPose;
        CurResult.bIsValid = true;

        // 运行相机装备的根节点
        FCameraNodeEvaluator* RootEvaluator = Entry.RootEvaluator->GetRootEvaluator();
        if (RootEvaluator)
        {
            RootEvaluator->Run(CurParams, CurResult);
        }
    }
}

Step 4: 后混合执行 (InternalPostBlendExecute)

void FTransientBlendStackCameraNodeEvaluator::InternalPostBlendExecute(
    TArrayView<FResolvedEntry> ResolvedEntries,
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    int32 PopEntriesBelow = INDEX_NONE;

    for (FResolvedEntry& ResolvedEntry : ResolvedEntries)
    {
        FCameraRigEntry& Entry = ResolvedEntry.Entry;
        FCameraNodeEvaluationResult& CurResult = Entry.Result;

        if (!Entry.Flags.bIsFrozen)
        {
            // 调用混合节点的 BlendResults
            FBlendCameraNodeEvaluator* EntryBlendEvaluator = Entry.RootEvaluator->GetBlendEvaluator();
            if (EntryBlendEvaluator)
            {
                FCameraNodeBlendParams BlendParams(CurParams, CurResult);
                FCameraNodeBlendResult BlendResult(OutResult);
                EntryBlendEvaluator->BlendResults(BlendParams, BlendResult);

                // 如果混合完成且达到100%,标记弹出下方条目
                if (BlendResult.bIsBlendFull && BlendResult.bIsBlendFinished)
                {
                    PopEntriesBelow = ResolvedEntry.EntryIndex;
                }
            }
            else
            {
                OutResult.OverrideAll(CurResult);
                PopEntriesBelow = ResolvedEntry.EntryIndex;
            }
        }
        else
        {
            // 冻结条目直接覆盖结果
            OutResult.OverrideAll(CurResult);
            PopEntriesBelow = ResolvedEntry.EntryIndex;
        }
    }

    // 弹出已完全混合的条目(仅限 IsolatedTransient 模式)
    if (!Params.IsStatelessEvaluation())
    {
        const UBlendStackCameraNode* BlendStackNode = GetCameraNodeAs<UBlendStackCameraNode>();
        if (BlendStackNode->BlendStackType == ECameraBlendStackType::IsolatedTransient &&
            PopEntriesBelow != INDEX_NONE)
        {
            PopEntries(PopEntriesBelow);
            EntryExtraInfos.RemoveAt(0, PopEntriesBelow);
        }
    }
}

3.4 参数传递与结果收集

3.4.1 评估参数结构

// 源码位置: Public/Core/CameraNodeEvaluator.h:150
struct FCameraNodeEvaluationParams
{
    // 运行此评估的评估器
    FCameraSystemEvaluator* Evaluator = nullptr;

    // 负责此评估分支的评估上下文
    TSharedPtr<const FCameraEvaluationContext> EvaluationContext;

    // 评估的时间间隔
    float DeltaTime = 0.f;

    // 评估类型
    ECameraNodeEvaluationType EvaluationType = ECameraNodeEvaluationType::Standard;

    // 是否是此节点层次结构的第一帧评估
    bool bIsFirstFrame = false;

    // 是否是无状态评估(IK或视角预览)
    bool IsStatelessEvaluation() const
    {
        return EvaluationType == ECameraNodeEvaluationType::IK ||
               EvaluationType == ECameraNodeEvaluationType::ViewRotationPreview;
    }
};

3.4.2 评估结果结构

// 源码位置: Public/Core/CameraNodeEvaluator.h:173
struct FCameraNodeEvaluationResult
{
    // 相机姿态
    FCameraPose CameraPose;

    // 变量表
    FCameraVariableTable VariableTable;

    // 上下文数据表
    FCameraContextDataTable ContextDataTable;

    // 相机装备关节列表
    FCameraRigJoints CameraRigJoints;

    // 后处理设置
    FPostProcessSettingsCollection PostProcessSettings;

    // 当前帧是否是相机切镜
    bool bIsCameraCut = false;

    // 结果是否有效
    bool bIsValid = false;

public:
    // 重置为默认(无效)状态
    void Reset();

    // 重置本帧写入标志
    void ResetFrameFlags();

    // 用另一个结果覆盖
    void OverrideAll(const FCameraNodeEvaluationResult& OtherResult, bool bIncludePrivateValues = false);

    // 向另一个结果插值
    void LerpAll(const FCameraNodeEvaluationResult& ToResult, float BlendFactor, bool bIncludePrivateValues = false);

    // 序列化
    void Serialize(FArchive& Ar);
};

3.4.3 数据流向图

graph LR subgraph 输入 A[FCameraNodeEvaluationParams] B[上下文初始结果] C[参数设置器服务] end subgraph 评估过程 D[预混合参数] E[节点树求值] F[结果混合] end subgraph 输出 G[FCameraNodeEvaluationResult] H[CameraPose] I[VariableTable] J[PostProcessSettings] end A --> D B --> D C --> D D --> E E --> F F --> G G --> H G --> I G --> J

3.4.4 结果混合方式

// 完全覆盖
void FCameraNodeEvaluationResult::OverrideAll(const FCameraNodeEvaluationResult& OtherResult, bool bIncludePrivateValues)
{
    CameraPose.OverrideAll(OtherResult.CameraPose);
    VariableTable.OverrideAll(OtherResult.VariableTable, bIncludePrivateValues);
    ContextDataTable.OverrideAll(OtherResult.ContextDataTable);
    PostProcessSettings.OverrideAll(OtherResult.PostProcessSettings);
    bIsCameraCut = OtherResult.bIsCameraCut;
}

// 插值混合
void FCameraNodeEvaluationResult::LerpAll(const FCameraNodeEvaluationResult& ToResult, float BlendFactor, bool bIncludePrivateValues)
{
    CameraPose.LerpAll(ToResult.CameraPose, BlendFactor);
    VariableTable.LerpAll(ToResult.VariableTable, BlendFactor, bIncludePrivateValues);
    // ContextDataTable 不插值
    PostProcessSettings.LerpAll(ToResult.PostProcessSettings, BlendFactor);
    bIsCameraCut = ToResult.bIsCameraCut;
}

3.5 流程图与时序图

3.5.1 完整评估时序图

sequenceDiagram participant Game as 游戏框架 participant CSE as FCameraSystemEvaluator participant Svc as EvaluationServices participant EC as FCameraEvaluationContext participant DE as FCameraDirectorEvaluator participant Root as FDefaultRootCameraNodeEvaluator participant Base as FPersistentBlendStack participant Main as FTransientBlendStack participant Global as FPersistentBlendStack participant Visual as FPersistentBlendStack participant Entry as FCameraRigEntry participant Node as FCameraNodeEvaluator Game->>CSE: Update(DeltaTime) activate CSE CSE->>CSE: ResetFrameFlags() CSE->>CSE: AutoResetValues() CSE->>Svc: PreUpdate() activate Svc Note over Svc: CameraShakeService<br/>CameraModifierService<br/>ParameterSetterService Svc-->>CSE: 完成 deactivate Svc CSE->>EC: GetActiveContext() EC-->>CSE: ActiveContext CSE->>DE: Run(DirectorParams, DirectorResult) activate DE DE-->>CSE: ActivationRequests deactivate DE loop 每个激活请求 CSE->>Root: ExecuteCameraDirectorRequest(Request) end CSE->>Root: Run(NodeParams, RootNodeResult) activate Root Root->>Base: Run(Params, Result) activate Base Base->>Base: 遍历所有条目 loop 每个Base条目 Base->>Node: Run(Params, EntryResult) Node-->>Base: EntryResult Base->>Base: 叠加到OutResult end Base-->>Root: BaseResult deactivate Base Root->>Main: Run(Params, Result) activate Main Main->>Main: InternalPreBlendPrepare() Main->>Main: InternalPreBlendExecute() Main->>Entry: 遍历所有条目 loop 每个Main条目 Main->>Node: Run(Params, EntryResult) Node-->>Main: EntryResult end Main->>Main: InternalPostBlendExecute() Main->>Main: PopEntriesIfNeeded() Main-->>Root: MainResult deactivate Main Root->>Global: Run(Params, Result) Global-->>Root: GlobalResult Root->>Root: SetPreVisualLayerResult() Root->>Visual: Run(Params, Result) Visual-->>Root: VisualResult Root-->>CSE: FinalResult deactivate Root CSE->>Svc: PostUpdate() activate Svc Svc-->>CSE: 完成 deactivate Svc CSE->>CSE: HarvestResult() CSE-->>Game: 完成 deactivate CSE Game->>CSE: GetEvaluatedCameraView(DesiredView) CSE-->>Game: FMinimalViewInfo

3.5.2 混合栈详细流程

stateDiagram-v2 [*] --> PreBlendPrepare PreBlendPrepare --> PreBlendExecute: 参数收集完成 note right of PreBlendPrepare - 复制输入变量 - 应用上下文覆盖 - 应用参数设置器 - 更新预混合参数 end note PreBlendExecute --> Update: 预混合完成 note right of PreBlendExecute - 混合输入变量 - 调用 BlendParameters - 写回预混合值 end note Update --> PostBlendExecute: 节点评估完成 note right of Update - 运行每个条目的根节点 - 跳过冻结条目 - 产生独立结果 end note PostBlendExecute --> RunFinished: 结果混合完成 note right of PostBlendExecute - 调用 BlendResults - 检测完成条件 - 弹出已完成条目 end note RunFinished --> [*]

3.5.3 关键帧时序

帧 N:
┌─────────────────────────────────────────────────────────────────────┐
│ PreUpdate Services                                                  │
├─────────────────────────────────────────────────────────────────────┤
│ Director: 激活 CameraRig_B                                          │
├─────────────────────────────────────────────────────────────────────┤
│ Main BlendStack:                                                    │
│   [CameraRig_A] ← 正在混合出去 (blend=0.3)                           │
│   [CameraRig_B] ← 新激活,正在混合进来 (blend=0.7)                    │
├─────────────────────────────────────────────────────────────────────┤
│ PostUpdate Services                                                 │
└─────────────────────────────────────────────────────────────────────┘

帧 N+1:
┌─────────────────────────────────────────────────────────────────────┐
│ PreUpdate Services                                                  │
├─────────────────────────────────────────────────────────────────────┤
│ Director: 无新请求                                                  │
├─────────────────────────────────────────────────────────────────────┤
│ Main BlendStack:                                                    │
│   [CameraRig_A] ← 混合进度继续 (blend=0.1)                           │
│   [CameraRig_B] ← 混合进度继续 (blend=0.9)                           │
├─────────────────────────────────────────────────────────────────────┤
│ PostUpdate Services                                                 │
└─────────────────────────────────────────────────────────────────────┘

帧 N+2:
┌─────────────────────────────────────────────────────────────────────┐
│ PreUpdate Services                                                  │
├─────────────────────────────────────────────────────────────────────┤
│ Director: 无新请求                                                  │
├─────────────────────────────────────────────────────────────────────┤
│ Main BlendStack:                                                    │
│   [CameraRig_B] ← 混合完成 (blend=1.0),CameraRig_A 被弹出          │
├─────────────────────────────────────────────────────────────────────┤
│ PostUpdate Services                                                 │
└─────────────────────────────────────────────────────────────────────┘

4. 关键模块详解

4.1 节点系统 (Nodes)

节点系统是 GameplayCameras 的核心,通过组合各种节点来构建复杂的相机行为。

4.1.1 节点组合模式

节点采用组合模式(Composite Pattern),允许将多个节点组合成树形结构:

UCameraRigAsset
└── RootNode: UArrayCameraNode (Sequence)
    ├── [0] UAttachToPlayerPawnCameraNode    # 附加到玩家
    ├── [1] UBoomArmCameraNode               # 吊臂控制
    │   └── InputSlot: UInput2DCameraNode    # 输入处理
    ├── [2] UCollisionPushCameraNode         # 碰撞检测
    └── [3] UDampenRotationCameraNode        # 旋转阻尼

4.1.2 节点输入/输出槽

节点通过(Slot)机制连接,支持数据流和控制流:

// 输入槽示例 - BoomArmCameraNode.h:59
// ObjectTreeGraphPinDirection=Input 表示这是一个输入槽
UPROPERTY(meta=(ObjectTreeGraphPinDirection=Input))
TObjectPtr<UInput2DCameraNode> InputSlot;

4.1.3 节点评估流程

每个节点的评估器实现 OnRun 方法:

// 典型的节点评估实现
void FBoomArmCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    const UBoomArmCameraNode* Data = GetCameraNodeAs<UBoomArmCameraNode>();

    // 1. 从变量表获取参数值
    const FVector BoomOffset = Data->BoomOffset.GetValue(OutResult.VariableTable);

    // 2. 获取输入(如果有子节点)
    if (InputSlotEvaluator)
    {
        InputSlotEvaluator->Run(Params, OutResult);
    }

    // 3. 应用节点逻辑
    FVector NewLocation = OutResult.CameraPose.GetLocation() + BoomOffset;
    OutResult.CameraPose.SetLocation(NewLocation);
}

4.1.4 Sequence 节点详解

源码位置: Public/Nodes/Common/ArrayCameraNode.h

Sequence 节点是最常用的组合节点,按顺序执行子节点:

UCLASS(MinimalAPI, meta=(DisplayName="Sequence", CameraNodeCategories="Common,Utility"))
class UArrayCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    // 子节点数组 - 按顺序执行
    UPROPERTY()
    TArray<TObjectPtr<UCameraNode>> Children;
};

评估器实现(简化版):

void FArrayCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    // 按顺序执行每个子节点
    for (FCameraNodeEvaluator* ChildEvaluator : ChildEvaluators)
    {
        if (ChildEvaluator)
        {
            ChildEvaluator->Run(Params, OutResult);
        }
    }
}

4.2 混合系统 (Blends)

混合系统负责在多个相机装备之间平滑过渡。

4.2.1 混合节点基类

源码位置: Public/Core/BlendCameraNode.h:116

class FBlendCameraNodeEvaluator : public FCameraNodeEvaluator
{
public:
    // 混合参数
    void BlendParameters(const FCameraNodePreBlendParams& Params, FCameraNodePreBlendResult& OutResult);

    // 混合结果
    void BlendResults(const FCameraNodeBlendParams& Params, FCameraNodeBlendResult& OutResult);

    // 从中断的混合初始化
    bool InitializeFromInterruption(const FCameraNodeBlendInterruptionParams& Params);

    // 反向混合
    bool SetReversed(bool bInReverse);

protected:
    virtual void OnBlendParameters(const FCameraNodePreBlendParams& Params, FCameraNodePreBlendResult& OutResult) {}
    virtual void OnBlendResults(const FCameraNodeBlendParams& Params, FCameraNodeBlendResult& OutResult) {}
};

4.2.2 内置混合类型

混合节点 说明 源码位置
ULinearBlendCameraNode 线性插值 Nodes/Blends/LinearBlendCameraNode.h
USmoothBlendCameraNode 平滑步进插值 Nodes/Blends/SmoothBlendCameraNode.h
UOrbitBlendCameraNode 轨道旋转混合 Nodes/Blends/OrbitBlendCameraNode.h
UPopBlendCameraNode 立即切换(无混合) Nodes/Blends/PopBlendCameraNode.h
ULocationRotationBlendCameraNode 位置/旋转分离混合 Nodes/Blends/LocationRotationBlendCameraNode.h

4.2.3 Smooth Blend 示例

源码位置: Public/Nodes/Blends/SmoothBlendCameraNode.h

UCLASS(MinimalAPI)
class USmoothBlendCameraNode : public USimpleFixedTimeBlendCameraNode
{
    GENERATED_BODY()

public:
    // 平滑算法类型
    UPROPERTY(EditAnywhere, Category=Blending)
    ESmoothCameraBlendType BlendType;

    void SetCameraBlendType(ESmoothCameraBlendType BlendTypeIn) { BlendType = BlendTypeIn; }
};

// 平滑算法类型
enum class ESmoothCameraBlendType
{
    SmoothStep,      // 3t² - 2t³
    SmootherStep     // 6t⁵ - 15t⁴ + 10t³
};

评估器实现(简化版):

void FSmoothBlendCameraNodeEvaluator::OnBlendResults(
    const FCameraNodeBlendParams& Params,
    FCameraNodeBlendResult& OutResult)
{
    const USmoothBlendCameraNode* Data = GetCameraNodeAs<USmoothBlendCameraNode>();

    // 计算进度
    float Progress = FMath::Clamp(ElapsedTime / TotalDuration, 0.f, 1.f);

    // 应用平滑函数
    float BlendFactor;
    switch (Data->BlendType)
    {
        case ESmoothCameraBlendType::SmootherStep:
            BlendFactor = 6.f * FMath::Pow(Progress, 5) -
                         15.f * FMath::Pow(Progress, 4) +
                         10.f * FMath::Pow(Progress, 3);
            break;
        case ESmoothCameraBlendType::SmoothStep:
        default:
            BlendFactor = Progress * Progress * (3.f - 2.f * Progress);
            break;
    }

    // 执行插值
    OutResult.BlendedResult.LerpAll(Params.ChildResult, BlendFactor);

    // 更新状态
    OutResult.bIsBlendFull = (Progress >= 1.f);
    OutResult.bIsBlendFinished = (Progress >= 1.f);

    ElapsedTime += Params.ChildParams.DeltaTime;
}

4.2.4 过渡系统

源码位置: Public/Core/CameraRigTransition.h

过渡定义了相机装备切换时的行为:

UCLASS(MinimalAPI)
class UCameraRigTransition : public UObject
{
    GENERATED_BODY()

public:
    // 条件列表 - 必须全部通过才使用此过渡
    UPROPERTY(Instanced, meta=(ObjectTreeGraphPinDirection=Input))
    TArray<TObjectPtr<UCameraRigTransitionCondition>> Conditions;

    // 使用的混合节点
    UPROPERTY(Instanced)
    TObjectPtr<UBlendCameraNode> Blend;

    // 初始朝向设置
    UPROPERTY(EditAnywhere, Category="Transition")
    ECameraRigInitialOrientation InitialOrientation;

    // 是否允许相机装备合并
    UPROPERTY(EditAnywhere, Category="Advanced")
    bool bAllowCameraRigMerging = false;
};

初始朝向模式

enum class ECameraRigInitialOrientation
{
    None,                    // 默认朝向
    ContextYawPitch,         // 使用上下文的初始朝向
    PreviousYawPitch,        // 继承前一个相机的朝向
    PreviousAbsoluteTarget,  // 指向前一个相机的目标点
    PreviousRelativeTarget   // 指向前一个相机的相对目标
};

4.3 层系统 (Layers)

GameplayCameras 采用四层架构来组织相机效果:

4.3.1 层定义

// 源码位置: Public/Core/CameraRigEvaluationInfo.h
enum class ECameraRigLayer
{
    None = 0,

    // 基础层 - 持久化、叠加
    // 适用于:始终运行的基础效果(如跟随、附加)
    Base = 1 << 0,

    // 主层 - 瞬态、混合
    // 适用于:游戏玩法相机(如第三人称、第一人称)
    Main = 1 << 1,

    // 全局层 - 持久化、叠加
    // 适用于:全局效果(如震动、天气)
    Global = 1 << 2,

    // 视觉层 - 持久化、叠加
    // 适用于:后处理效果(如景深、色彩校正)
    Visual = 1 << 3
};

4.3.2 层特性对比

混合栈类型 自动弹出 典型用途
Base AdditivePersistent 跟随附加、基础变换
Main IsolatedTransient 游戏玩法相机切换
Global AdditivePersistent 全局效果、震动
Visual AdditivePersistent 后处理效果

4.3.3 层评估顺序

// 源码位置: Private/Core/DefaultRootCameraNode.cpp:77
void FDefaultRootCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    // 1. Base Layer
    BaseLayer->Run(Params, OutResult);

    // 2. Main Layer
    MainLayer->Run(Params, OutResult);

    // 3. Global Layer
    GlobalLayer->Run(Params, OutResult);

    // 保存 Pre-Visual 结果
    SetPreVisualLayerResult(OutResult);

    // 4. Visual Layer (跳过 IK 和视角预览)
    if (Params.EvaluationType != ECameraNodeEvaluationType::IK &&
        Params.EvaluationType != ECameraNodeEvaluationType::ViewRotationPreview)
    {
        VisualLayer->Run(Params, OutResult);
    }
}

4.3.4 层架构图

┌─────────────────────────────────────────────────────────────────────┐
│                          最终相机结果                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Visual Layer (视觉层)                                       │   │
│   │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐       │   │
│   │  │ PostProcess  │  │  Filmback    │  │  AutoFocus   │       │   │
│   │  └──────────────┘  └──────────────┘  └──────────────┘       │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              ▲ 叠加                                 │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Global Layer (全局层)                                       │   │
│   │  ┌──────────────┐  ┌──────────────┐                         │   │
│   │  │  Shake       │  │  Modifier    │                         │   │
│   │  └──────────────┘  └──────────────┘                         │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              ▲ 叠加                                 │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Main Layer (主层) - 混合栈                                  │   │
│   │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐       │   │
│   │  │  3rd Person  │──│   Blend      │──│  1st Person  │       │   │
│   │  │  (混合出)    │  │   (100%)     │  │  (混合入)    │       │   │
│   │  └──────────────┘  └──────────────┘  └──────────────┘       │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              ▲ 叠加                                 │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Base Layer (基础层)                                         │   │
│   │  ┌──────────────────────────────────────────────────────┐   │   │
│   │  │  AttachToPlayerPawn                                   │   │   │
│   │  └──────────────────────────────────────────────────────┘   │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

4.4 服务系统 (Evaluation Services)

服务系统提供横切关注点,在相机评估前后执行额外逻辑。

4.4.1 服务基类

源码位置: Public/Core/CameraEvaluationService.h

class FCameraEvaluationService : public TSharedFromThis<FCameraEvaluationService>
{
public:
    // 初始化
    void Initialize(const FCameraEvaluationServiceInitializeParams& Params);

    // 预更新(在节点树评估前)
    void PreUpdate(const FCameraEvaluationServiceUpdateParams& Params,
                   FCameraEvaluationServiceUpdateResult& OutResult);

    // 后更新(在节点树评估后)
    void PostUpdate(const FCameraEvaluationServiceUpdateParams& Params,
                    FCameraEvaluationServiceUpdateResult& OutResult);

    // 销毁
    void Teardown(const FCameraEvaluationServiceTeardownParams& Params);

    // 根节点事件通知
    void NotifyRootCameraNodeEvent(const FRootCameraNodeCameraRigEvent& InEvent);

protected:
    virtual void OnInitialize(...) {}
    virtual void OnPreUpdate(...) {}
    virtual void OnPostUpdate(...) {}
    virtual void OnTeardown(...) {}
    virtual void OnRootCameraNodeEvent(...) {}
};

4.4.2 服务标志

enum class ECameraEvaluationServiceFlags
{
    None = 0,
    NeedsPreUpdate = 1 << 0,           // 需要预更新回调
    NeedsPostUpdate = 1 << 1,          // 需要后更新回调
    NeedsRootCameraNodeEvents = 1 << 2, // 需要根节点事件

    Default = NeedsPreUpdate | NeedsPostUpdate | NeedsRootCameraNodeEvents
};

4.4.3 内置服务

服务 功能 源码位置
FCameraShakeService 管理相机震动 Services/CameraShakeService.h
FCameraModifierService 应用相机修饰符 Services/CameraModifierService.h
FCameraParameterSetterService 处理参数设置请求 Services/CameraParameterSetterService.h
FOrientationInitializationService 初始化相机朝向 Services/OrientationInitializationService.h

4.4.4 服务注册与发现

// 源码位置: Private/Core/CameraSystemEvaluator.cpp:177
void FCameraSystemEvaluator::RegisterEvaluationService(
    TSharedRef<FCameraEvaluationService> EvaluationService)
{
    EvaluationServices.Add(EvaluationService);

    FCameraEvaluationServiceInitializeParams InitParams;
    InitParams.Evaluator = this;
    EvaluationService->Initialize(InitParams);
}

// 查找服务
template<typename EvaluationServiceType>
TSharedPtr<EvaluationServiceType> FindEvaluationService() const
{
    TSharedPtr<FCameraEvaluationService> Service =
        FindEvaluationService(EvaluationServiceType::StaticTypeID());
    return StaticCastSharedPtr<EvaluationServiceType>(Service);
}

4.5 调试系统 (Debug)

4.5.1 调试宏和开关

// 源码位置: Public/GameplayCameras.h
#ifndef UE_GAMEPLAY_CAMERAS_DEBUG
    #if UE_ENABLE_DEBUG_DRAWING
        #define UE_GAMEPLAY_CAMERAS_DEBUG 1
    #else
        #define UE_GAMEPLAY_CAMERAS_DEBUG 0
    #endif
#endif

4.5.2 调试块系统

调试信息通过调试块(Debug Block)系统组织:

// 源码位置: Public/Debug/CameraDebugBlock.h
class FCameraDebugBlock
{
public:
    virtual void OnDebugDraw(const FCameraDebugBlockDrawParams& Params,
                             FCameraDebugRenderer& Renderer) {}

    virtual void OnSerialize(FArchive& Ar) {}

protected:
    TArray<TSharedPtr<FCameraDebugBlock>> Children;
};

4.5.3 调试渲染器

class FCameraDebugRenderer
{
public:
    // 绘制线条
    void DrawLine(const FVector3d& Start, const FVector3d& End,
                  const FLinearColor& Color, float Thickness = 1.f);

    // 绘制文字
    void DrawText(const FString& Text, const FVector3d& Location,
                  const FLinearColor& Color);

    // 绘制坐标轴
    void DrawAxes(const FTransform3d& Transform, float Size = 10.f);
};

4.6 导演系统 (Directors)

导演系统控制相机装备的激活和停用。

4.6.1 导演基类

源码位置: Public/Core/CameraDirector.h

UCLASS(MinimalAPI, Abstract, DefaultToInstanced)
class UCameraDirector : public UObject
{
    GENERATED_BODY()

public:
    // 构建评估器
    FCameraDirectorEvaluatorPtr BuildEvaluator(FCameraDirectorEvaluatorBuilder& Builder) const;

    // 构建验证
    void BuildCameraDirector(UE::Cameras::FCameraBuildLog& BuildLog);

    // 收集使用的相机装备
    void GatherRigUsageInfo(FCameraDirectorRigUsageInfo& UsageInfo) const;

protected:
    virtual FCameraDirectorEvaluatorPtr OnBuildEvaluator(FCameraDirectorEvaluatorBuilder& Builder) const
    {
        return nullptr;
    }

    virtual void OnBuildCameraDirector(UE::Cameras::FCameraBuildLog& BuildLog) {}
    virtual void OnGatherRigUsageInfo(FCameraDirectorRigUsageInfo& UsageInfo) const {}

public:
    // 相机装备代理重定向表
    UPROPERTY(EditAnywhere, Category="Evaluation")
    FCameraRigProxyRedirectTable CameraRigProxyRedirectTable;
};

4.6.2 内置导演类型

导演 说明 源码位置
USingleCameraDirector 返回单个固定相机装备 Directors/SingleCameraDirector.h
UBlueprintCameraDirector 蓝图实现的导演 Directors/BlueprintCameraDirector.h
UPriorityQueueCameraDirector 基于优先队列的导演 Directors/PriorityQueueCameraDirector.h
UStateTreeCameraDirector 基于状态树的导演 Directors/StateTreeCameraDirector.h

4.6.3 SingleCameraDirector 示例

源码位置: Public/Directors/SingleCameraDirector.h

UCLASS(MinimalAPI, EditInlineNew)
class USingleCameraDirector : public UCameraDirector
{
    GENERATED_BODY()

public:
    USingleCameraDirector(const FObjectInitializer& ObjectInit);

protected:
    virtual FCameraDirectorEvaluatorPtr OnBuildEvaluator(
        FCameraDirectorEvaluatorBuilder& Builder) const override;

    virtual void OnBuildCameraDirector(UE::Cameras::FCameraBuildLog& BuildLog) override;

    virtual void OnGatherRigUsageInfo(FCameraDirectorRigUsageInfo& UsageInfo) const override;

public:
    // 每帧运行的相机装备
    UPROPERTY(EditAnywhere, Category=Common, meta=(UseSelfCameraRigPicker=true))
    TObjectPtr<UCameraRigAsset> CameraRig;
};

4.6.4 导演评估流程

sequenceDiagram participant CSE as FCameraSystemEvaluator participant DE as FCameraDirectorEvaluator participant Root as FRootCameraNodeEvaluator CSE->>DE: Run(DirectorParams, DirectorResult) activate DE Note over DE: 评估逻辑决定<br/>激活/停用哪些相机装备 DE->>DE: 生成 ActivationRequests DE-->>CSE: DirectorResult (包含 Requests) deactivate DE loop 每个请求 CSE->>Root: ExecuteCameraDirectorRequest(Request) alt 激活请求 Root->>Root: OnActivateCameraRig() Note over Root: 将相机装备推入<br/>对应的混合栈层 else 停用请求 Root->>Root: OnDeactivateCameraRig() Note over Root: 从混合栈层<br/>移除或冻结相机装备 end end

4.6.5 相机装备代理系统

导演可以使用代理(Proxy)来间接引用相机装备:

// 代理重定向表
UPROPERTY(EditAnywhere, Category="Evaluation")
FCameraRigProxyRedirectTable CameraRigProxyRedirectTable;

// 使用示例
// 在蓝图中:设置 CameraRigProxy = "CombatCamera"
// 在数据表中:将 "CombatCamera" 映射到实际的 UCameraRigAsset

这种设计允许:

  • 在蓝图/状态树中使用逻辑名称
  • 运行时通过数据表映射到实际资产
  • 支持不同场景使用不同的相机装备实现

5. API 设计说明

5.1 公共 API

5.1.1 主要公共头文件

头文件 主要类/结构 用途
CameraSystemEvaluator.h FCameraSystemEvaluator 相机系统入口
CameraPose.h FCameraPose 相机姿态数据
CameraNode.h UCameraNode 节点基类
CameraNodeEvaluator.h FCameraNodeEvaluator 评估器基类
CameraRigAsset.h UCameraRigAsset 相机装备资产
CameraAsset.h UCameraAsset 相机资产
CameraVariableTable.h FCameraVariableTable 变量表
CameraParameters.h F*CameraParameter 参数类型
GameplayCameraComponent.h UGameplayCameraComponent 组件集成

5.1.2 命名空间

所有核心类型都在 UE::Cameras 命名空间中:

namespace UE::Cameras
{
    class FCameraSystemEvaluator;
    class FCameraNodeEvaluator;
    class FCameraEvaluationContext;
    class FCameraEvaluationService;
    // ...
}

5.2 核心数据结构

5.2.1 FCameraPose (相机姿态)

源码位置: Public/Core/CameraPose.h

FCameraPose 是描述相机完整状态的核心结构:

USTRUCT()
struct GAMEPLAYCAMERAS_API FCameraPose
{
    GENERATED_BODY()

public:
    // 变换属性
    FVector3d Location;          // 世界空间位置
    FRotator3d Rotation;         // 世界空间旋转
    double TargetDistance;       // 到目标的距离

    // 视场属性
    float FieldOfView;           // 水平视场角(度)
    float FocalLength;           // 焦距(毫米)
    float OrthographicWidth;     // 正交宽度

    // 物理相机属性
    float Aperture;              // 光圈(f-stops)
    float ShutterSpeed;          // 快门速度(1/秒)
    float FocusDistance;         // 对焦距离
    float SensorWidth;           // 传感器宽度(毫米)
    float SensorHeight;          // 传感器高度(毫米)
    float ISO;                   // ISO 感光度
    float SqueezeFactor;         // 变形镜头压缩因子
    float Overscan;              // 过扫描百分比
    int32 DiaphragmBladeCount;   // 光圈叶片数

    // 裁剪平面
    float NearClippingPlane;     // 近裁剪距离
    float FarClippingPlane;      // 远裁剪距离

    // 标志
    bool EnablePhysicalCamera;   // 启用物理相机
    bool ConstrainAspectRatio;   // 约束宽高比
    ECameraProjectionMode::Type ProjectionMode;  // 投影模式

    // 变更追踪
    FCameraPoseFlags ChangedFlags;

public:
    // 工具方法
    FTransform3d GetTransform() const;
    void SetTransform(FTransform3d Transform, bool bForceSet = false);
    double GetEffectiveFieldOfView(bool bIncludeOverscan = true) const;
    double GetSensorAspectRatio() const;
    FRay3d GetAimRay() const;
    FVector3d GetTarget() const;

    // 插值方法
    void OverrideAll(const FCameraPose& OtherPose);
    void OverrideChanged(const FCameraPose& OtherPose);
    void LerpAll(const FCameraPose& ToPose, float Factor);
    void LerpChanged(const FCameraPose& ToPose, float Factor);
};

使用示例

// 获取当前相机位置
FVector3d CurrentLocation = CameraPose.GetLocation();

// 设置新的相机位置(自动设置 ChangedFlags)
CameraPose.SetLocation(NewLocation);

// 插值到目标姿态
FromPose.LerpAll(ToPose, 0.5f);  // 50% 插值

// 获取相机瞄准射线
FRay3d AimRay = CameraPose.GetAimRay();

// 计算有效视场角(考虑焦距或视场角设置)
double EffectiveFOV = CameraPose.GetEffectiveFieldOfView();

5.2.2 FCameraVariableTable (变量表)

源码位置: Public/Core/CameraVariableTable.h

FCameraVariableTable可混合的参数存储容器:

class FCameraVariableTable
{
public:
    // 初始化
    void Initialize(const FCameraVariableTableAllocationInfo& AllocationInfo);
    void AddVariable(const FCameraVariableDefinition& VariableDefinition);

    // Getter 方法
    template<typename ValueType>
    const ValueType* FindValue(FCameraVariableID VariableID) const;

    template<typename ValueType>
    const ValueType& GetValue(FCameraVariableID VariableID) const;

    template<typename ValueType>
    ValueType GetValue(FCameraVariableID VariableID, typename TCallTraits<ValueType>::ParamType DefaultValue) const;

    template<typename VariableAssetType>
    typename VariableAssetType::ValueType GetValue(const VariableAssetType* VariableAsset) const;

    // Setter 方法
    template<typename ValueType>
    void SetValue(FCameraVariableID VariableID, typename TCallTraits<ValueType>::ParamType Value);

    template<typename VariableAssetType>
    void SetValue(const VariableAssetType* VariableAsset,
                  typename TCallTraits<typename VariableAssetType::ValueType>::ParamType Value,
                  bool bCreateIfMissing = false);

    // 插值方法
    void OverrideAll(const FCameraVariableTable& OtherTable, bool bIncludePrivateValues = false);
    void Override(const FCameraVariableTable& OtherTable, ECameraVariableTableFilter Filter);
    void LerpAll(const FCameraVariableTable& ToTable, float Factor, bool bIncludePrivateValues = false);
    void Lerp(const FCameraVariableTable& ToTable, ECameraVariableTableFilter Filter, float Factor);

    // 状态管理
    bool IsValueWritten(FCameraVariableID VariableID) const;
    bool IsValueWrittenThisFrame(FCameraVariableID VariableID) const;
    void ClearAllWrittenThisFrameFlags();
    void AutoResetValues();
};

过滤器类型

enum class ECameraVariableTableFilter
{
    None = 0,
    PublicOnly = 1 << 0,    // 只包含公共变量
    InputOnly = 1 << 1,     // 只包含输入变量
    KnownOnly = 1 << 2,     // 只包含两个表共有的数据
    ChangedOnly = 1 << 3,   // 只包含本帧写入的变量
};

使用示例

// 设置变量值
VariableTable.SetValue<float>(ZoomVariableID, 2.0f);

// 通过变量资产设置
VariableTable.SetValue(ZoomVariableAsset, 2.0f);

// 获取变量值(带默认值)
float Zoom = VariableTable.GetValue<float>(ZoomVariableID, 1.0f);

// 通过变量资产获取
float Zoom = VariableTable.GetValue(ZoomVariableAsset);

// 混合两个变量表
FromTable.LerpAll(ToTable, BlendFactor);

// 只混合输入变量
FromTable.Lerp(ToTable, ECameraVariableTableFilter::InputOnly, BlendFactor);

5.2.3 FCameraContextDataTable (上下文数据表)

源码位置: Public/Core/CameraContextDataTable.h

FCameraContextDataTable不可混合的上下文数据存储:

class FCameraContextDataTable
{
public:
    // 初始化
    void Initialize(const FCameraContextDataTableAllocationInfo& AllocationInfo);
    void AddData(const FCameraContextDataDefinition& DataDefinition);

    // 类型化 Getter
    const FName& GetNameData(FCameraContextDataID InID) const;
    const FString& GetStringData(FCameraContextDataID InID) const;
    UObject* GetObjectData(FCameraContextDataID InID) const;
    UClass* GetClassData(FCameraContextDataID InID) const;

    template<typename EnumType>
    EnumType GetEnumData(FCameraContextDataID InID) const;

    template<typename StructType>
    const StructType& GetStructData(FCameraContextDataID InID) const;

    // 类型化 Setter
    void SetNameData(FCameraContextDataID InID, const FName& InData);
    void SetStringData(FCameraContextDataID InID, const FString& InData);
    void SetObjectData(FCameraContextDataID InID, UObject* InData);

    template<typename EnumType>
    void SetEnumData(FCameraContextDataID InID, EnumType InData);

    template<typename StructType>
    void SetStructData(FCameraContextDataID InID, const StructType& InData);

    // 数组支持
    template<typename ValueType>
    TConstArrayView<ValueType> TryGetArrayData(FCameraContextDataID InID) const;

    template<typename StructType>
    void SetStructArrayData(FCameraContextDataID InID, TConstArrayView<StructType> InData);

    // 覆盖方法(无插值)
    void OverrideAll(const FCameraContextDataTable& OtherTable);
    void OverrideKnown(const FCameraContextDataTable& OtherTable);
};

使用示例

// 存储目标 Actor
ContextDataTable.SetObjectData(TargetActorID, MyTargetActor);

// 获取目标 Actor
AActor* Target = ContextDataTable.GetObjectData<AActor>(TargetActorID);

// 存储自定义结构体
FMyCameraSettings Settings;
Settings.bEnableFeature = true;
Settings.Intensity = 0.5f;
ContextDataTable.SetStructData(SettingsID, Settings);

// 读取自定义结构体
const FMyCameraSettings& Settings = ContextDataTable.GetStructData<FMyCameraSettings>(SettingsID);

// 存储枚举
ContextDataTable.SetEnumData<EMyCameraMode>(ModeID, EMyCameraMode::Combat);

// 存储数组
TArray<FVector> Waypoints;
ContextDataTable.SetStructArrayData(WaypointsID, Waypoints);

5.2.4 FCameraNodeEvaluationResult (评估结果)

源码位置: Public/Core/CameraNodeEvaluator.h:173

struct GAMEPLAYCAMERAS_API FCameraNodeEvaluationResult
{
    // 相机姿态
    FCameraPose CameraPose;

    // 变量表(可混合)
    FCameraVariableTable VariableTable;

    // 上下文数据表(不可混合)
    FCameraContextDataTable ContextDataTable;

    // 相机装备关节
    FCameraRigJoints CameraRigJoints;

    // 后处理设置
    FPostProcessSettingsCollection PostProcessSettings;

    // 状态标志
    bool bIsCameraCut = false;   // 是否是相机切镜
    bool bIsValid = false;       // 结果是否有效

public:
    // 重置方法
    void Reset();
    void ResetFrameFlags();

    // 组合方法
    void OverrideAll(const FCameraNodeEvaluationResult& OtherResult, bool bIncludePrivateValues = false);
    void LerpAll(const FCameraNodeEvaluationResult& ToResult, float BlendFactor, bool bIncludePrivateValues = false);

    // 序列化
    void Serialize(FArchive& Ar);

    // GC 支持
    void AddReferencedObjects(FReferenceCollector& Collector);
};

数据流向

FCameraNodeEvaluationResult
├── CameraPose (姿态)
│   ├── Location
│   ├── Rotation
│   ├── FieldOfView
│   └── ...
├── VariableTable (变量表 - 可混合)
│   ├── InputYaw
│   ├── InputPitch
│   └── CustomParameters...
├── ContextDataTable (上下文数据 - 不可混合)
│   ├── TargetActor
│   └── CustomStructs...
├── CameraRigJoints (关节)
├── PostProcessSettings (后处理)
└── Flags (bIsCameraCut, bIsValid)

5.3 参数系统 (Camera Parameters)

5.3.1 参数类型

源码位置: Public/Core/CameraParameters.h

GameplayCameras 提供了类型化的参数系统,支持从固定值或变量资产获取值:

// 基础类型参数
USTRUCT(BlueprintType)
struct FBooleanCameraParameter { ... };

USTRUCT(BlueprintType)
struct FInteger32CameraParameter { ... };

USTRUCT(BlueprintType)
struct FFloatCameraParameter { ... };

USTRUCT(BlueprintType)
struct FDoubleCameraParameter { ... };

// 向量类型参数
USTRUCT(BlueprintType)
struct FVector2fCameraParameter { ... };

USTRUCT(BlueprintType)
struct FVector3dCameraParameter { ... };

USTRUCT(BlueprintType)
struct FVector4dCameraParameter { ... };

// 旋转类型参数
USTRUCT(BlueprintType)
struct FRotator3dCameraParameter { ... };

// 变换类型参数
USTRUCT(BlueprintType)
struct FTransform3dCameraParameter { ... };

5.3.2 参数结构

每个参数包含三个关键属性:

USTRUCT(BlueprintType)
struct FFloatCameraParameter
{
    GENERATED_BODY()

    using ValueType = float;
    using VariableAssetType = UFloatCameraVariable;

    // 用户可调的默认值
    UPROPERTY(EditAnywhere, Interp, Category=Common)
    float Value = 0.f;

    // 变量 ID(运行时设置)
    UPROPERTY()
    FCameraVariableID VariableID;

    // 用户选择的变量资产
    UPROPERTY(EditAnywhere, Category=Common)
    TObjectPtr<UFloatCameraVariable> Variable;

    // 获取值的方法
    ValueType GetValue(const FCameraVariableTable& VariableTable) const;

    // 检查是否有覆盖
    bool HasOverride() const { return VariableID.IsValid(); }
    bool HasUserOverride() const { return Variable != nullptr; }
};

5.3.3 参数使用模式

模式 1:固定值

// 在节点定义中
UPROPERTY(EditAnywhere, Category=Common)
FFloatCameraParameter Duration;

// 设置默认值(编辑器或代码)
Duration.Value = 1.0f;

// 在评估器中获取值
float DurationValue = Duration.GetValue(OutResult.VariableTable);  // 返回 1.0f

模式 2:变量资产覆盖

// 创建变量资产
UFloatCameraVariable* SpeedVariable = NewObject<UFloatCameraVariable>();
SpeedVariable->Value = 5.0f;

// 在节点中设置变量引用
SpeedParameter.Variable = SpeedVariable;

// 在评估器中获取值
float Speed = SpeedParameter.GetValue(OutResult.VariableTable);  // 返回 5.0f

模式 3:运行时变量覆盖

// 游戏代码中动态设置变量
VariableTable.SetValue(SpeedVariableID, 10.0f);

// 评估时自动使用覆盖值
float Speed = SpeedParameter.GetValue(VariableTable);  // 返回 10.0f

5.3.4 实际案例:BoomArm 节点参数

// 节点定义
UCLASS()
class UBoomArmCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    // 吊臂偏移 - 使用向量参数
    UPROPERTY(EditAnywhere, Category=Common)
    FVector3dCameraParameter BoomOffset;

    // 最大前向插值因子 - 使用双精度参数
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter MaxForwardInterpolationFactor = -1.0;
};

// 评估器实现
void FBoomArmCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    const UBoomArmCameraNode* Data = GetCameraNodeAs<UBoomArmCameraNode>();

    // 从参数获取当前值(考虑变量覆盖)
    FVector BoomOffset = Data->BoomOffset.GetValue(OutResult.VariableTable);
    double MaxForward = Data->MaxForwardInterpolationFactor.GetValue(OutResult.VariableTable);

    // 使用值进行计算...
}

5.4 评估上下文 (Evaluation Context)

5.4.1 FCameraEvaluationContext 概述

源码位置: Public/Core/CameraEvaluationContext.h

class FCameraEvaluationContext : public TSharedFromThis<FCameraEvaluationContext>
{
public:
    // 获取所有者
    UObject* GetOwner() const;

    // 获取世界
    UWorld* GetWorld() const;

    // 获取玩家控制器
    APlayerController* GetPlayerController() const;

    // 获取相机资产
    const UCameraAsset* GetCameraAsset() const;

    // 获取初始结果
    const FCameraNodeEvaluationResult& GetInitialResult() const;
    FCameraNodeEvaluationResult& GetInitialResult();

    // 获取导演评估器
    FCameraDirectorEvaluator* GetDirectorEvaluator() const;

    // 获取父/子上下文
    TSharedPtr<const FCameraEvaluationContext> GetParentContext() const;
    TArrayView<const TSharedPtr<FCameraEvaluationContext>> GetChildrenContexts() const;

    // 获取视口大小
    FIntPoint GetViewportSize() const;

    // 条件结果
    const FCameraNodeEvaluationResult* GetConditionalResult(ECameraEvaluationDataCondition Condition) const;
    FCameraNodeEvaluationResult& GetOrAddConditionalResult(ECameraEvaluationDataCondition Condition);

    // 激活/停用
    void Activate(const FCameraEvaluationContextActivateParams& Params);
    void Deactivate(const FCameraEvaluationContextDeactivateParams& Params);
    bool IsActive() const;

    // 子上下文管理
    bool AddChildContext(TSharedRef<FCameraEvaluationContext> ChildContext);
    bool RemoveChildContext(TSharedRef<FCameraEvaluationContext> ChildContext);
};

5.4.2 上下文层次结构

┌─────────────────────────────────────────────────────────────────────┐
│                    FCameraEvaluationContextStack                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Context 2 (Top - Active)                                    │   │
│   │  └── UGameplayCameraComponent (CinematicCamera)             │   │
│   │      └── UCameraAsset (Cinematic)                           │   │
│   │          └── InitialResult                                  │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              ▲                                      │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Context 1 (Middle)                                          │   │
│   │  └── UGameplayCameraComponent (MainCamera)                   │   │
│   │      └── UCameraAsset (ThirdPerson)                         │   │
│   │          └── InitialResult                                  │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                              ▲                                      │
│   ┌─────────────────────────────────────────────────────────────┐   │
│   │  Context 0 (Bottom)                                          │   │
│   │  └── APlayerController                                       │   │
│   │      └── Default Context                                    │   │
│   └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5.4.3 初始结果使用

// 在评估前设置初始结果
FCameraNodeEvaluationResult& InitialResult = EvaluationContext->GetInitialResult();

// 设置初始相机姿态
InitialResult.CameraPose.SetLocation(PlayerLocation);
InitialResult.CameraPose.SetRotation(PlayerRotation);

// 设置初始变量
InitialResult.VariableTable.SetValue(MovementSpeedVariable, PlayerSpeed);

// 节点评估时会基于这些初始值进行计算

5.5 扩展点说明

5.5.1 扩展点概览

扩展点 基类 用途 文件位置
自定义节点 UCameraNode 新的相机行为 Core/CameraNode.h
自定义评估器 FCameraNodeEvaluator 节点的运行时逻辑 Core/CameraNodeEvaluator.h
自定义混合 UBlendCameraNode 新的混合算法 Core/BlendCameraNode.h
自定义导演 UCameraDirector 控制相机激活逻辑 Core/CameraDirector.h
自定义服务 FCameraEvaluationService 横切关注点 Core/CameraEvaluationService.h
自定义过渡条件 UCameraRigTransitionCondition 过渡条件判断 Core/CameraRigTransition.h

5.5.2 扩展宏速查

// 声明节点评估器
#define UE_DECLARE_CAMERA_NODE_EVALUATOR(ApiDeclSpec, ClassName)\
    UE_GAMEPLAY_CAMERAS_DECLARE_RTTI(ApiDeclSpec, ClassName, FCameraNodeEvaluator)

// 定义节点评估器
#define UE_DEFINE_CAMERA_NODE_EVALUATOR(ClassName)\
    UE_GAMEPLAY_CAMERAS_DEFINE_RTTI(ClassName)

// 声明混合节点评估器
#define UE_DECLARE_BLEND_CAMERA_NODE_EVALUATOR(ApiDeclSpec, ClassName)\
    UE_DECLARE_CAMERA_NODE_EVALUATOR_EX(ApiDeclSpec, ClassName, ::UE::Cameras::FBlendCameraNodeEvaluator)

// 声明评估服务
#define UE_DECLARE_CAMERA_EVALUATION_SERVICE(ApiDeclSpec, ClassName)\
    UE_GAMEPLAY_CAMERAS_DECLARE_RTTI(ApiDeclSpec, ClassName, FCameraEvaluationService)

// 定义评估服务
#define UE_DEFINE_CAMERA_EVALUATION_SERVICE(ClassName)\
    UE_GAMEPLAY_CAMERAS_DEFINE_RTTI(ClassName)

5.5.3 类型安全转换

// 安全转换
if (FBoomArmCameraNodeEvaluator* BoomEval = Evaluator->CastThis<FBoomArmCameraNodeEvaluator>())
{
    // 成功转换,可以安全使用
}

// 断言转换(确保类型正确)
FBoomArmCameraNodeEvaluator* BoomEval = Evaluator->CastThisChecked<FBoomArmCameraNodeEvaluator>();

// 类型检查
if (Evaluator->IsKindOf<FBoomArmCameraNodeEvaluator>())
{
    // 是 BoomArm 评估器
}

6. 节点类型参考

6.1 通用节点 (Common)

节点名称 说明 源文件
Sequence 按顺序执行多个子节点 ArrayCameraNode.h
Boom Arm 吊臂相机控制器,支持跟随和插值 BoomArmCameraNode.h
Offset 应用位置/旋转偏移 OffsetCameraNode.h
Set Location 直接设置相机位置 SetLocationCameraNode.h
Set Rotation 直接设置相机旋转 SetRotationCameraNode.h
Dampen Position 位置阻尼/平滑 DampenPositionCameraNode.h
Dampen Rotation 旋转阻尼/平滑 DampenRotationCameraNode.h
Field of View 设置视场角 FieldOfViewCameraNode.h
Clipping Planes 设置裁剪平面 ClippingPlanesCameraNode.h
Orthographic 正交投影设置 OrthographicCameraNode.h
Post Process 后处理效果设置 PostProcessCameraNode.h
Auto Focus 自动对焦 AutoFocusCameraNode.h
Body Parameters 物理相机机身参数 BodyParametersCameraNode.h
Lens Parameters 物理相机镜头参数 LensParametersCameraNode.h
Lens Calibration 镜头校准 LensCalibrationCameraNode.h
Filmback 胶片背设置 FilmbackCameraNode.h
Target Ray Cast 目标射线检测 TargetRayCastCameraNode.h
Spline Offset 沿样条偏移 SplineOffsetCameraNode.h
Spline Orbit 沿样条轨道 SplineOrbitCameraNode.h
Spline FOV 样条驱动的视场角 SplineFieldOfViewCameraNode.h
Camera Rig 嵌套相机装备 CameraRigCameraNode.h

6.1.1 Sequence 节点详解

┌─────────────────────────────────────────────────────────────┐
│                    Sequence (ArrayCameraNode)               │
├─────────────────────────────────────────────────────────────┤
│  按顺序执行所有子节点,后面的节点可以覆盖前面的结果        │
│                                                             │
│  典型用途:                                                  │
│  [0] AttachToPlayerPawn  →  附加到玩家                      │
│  [1] BoomArm             →  吊臂控制                        │
│  [2] CollisionPush       →  碰撞检测                        │
│  [3] DampenRotation      →  旋转平滑                        │
└─────────────────────────────────────────────────────────────┘

6.1.2 Boom Arm 节点详解

// 源码位置: Public/Nodes/Common/BoomArmCameraNode.h
UCLASS()
class UBoomArmCameraNode : public UCameraNode
{
    // 吊臂偏移(相对于附加点)
    UPROPERTY(EditAnywhere, Category=Common)
    FVector3dCameraParameter BoomOffset;

    // 吊臂长度
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter BoomLength;

    // 是否允许角色旋转影响相机
    UPROPERTY(EditAnywhere, Category=Common)
    bool bAllowUserControlRotation = true;

    // 输入槽
    UPROPERTY(meta=(ObjectTreeGraphPinDirection=Input))
    TObjectPtr<UInput2DCameraNode> InputSlot;
};

6.2 混合节点 (Blends)

节点名称 说明 源文件
Smooth Blend 平滑步进混合 SmoothBlendCameraNode.h
Linear Blend 线性插值混合 LinearBlendCameraNode.h
Simple Blend 简单固定时间混合 SimpleBlendCameraNode.h
Orbit Blend 轨道旋转混合 OrbitBlendCameraNode.h
Location Rotation Blend 位置/旋转分离混合 LocationRotationBlendCameraNode.h
Pop Blend 立即切换(无混合) PopBlendCameraNode.h
Reverse Blend 反向混合 ReverseBlendCameraNode.h
Interrupted Blend 中断后继续的混合 InterruptedBlendCameraNode.h

6.2.1 混合曲线对比

混合因子
1.0 ┤                         ●────────── SmoothStep
    │                    ●────
    │               ●───
0.5 ┤          ●───      ○────────────── Linear
    │     ●───      ○───
    │ ●───     ○───
0.0 ┤────────────────────────────────────► 时间
    0        0.5        1.0

SmoothStep: y = 3t² - 2t³ (更平滑的开始和结束)
Linear:     y = t        (匀速)

6.2.2 使用场景

场景 推荐混合节点 原因
一般切换 SmoothBlend 自然流畅
快速切换 LinearBlend (短时间) 可控速度
剧情切镜 PopBlend 无过渡
绕目标旋转 OrbitBlend 保持注视目标
不同维度混合 LocationRotationBlend 位置和旋转独立控制

6.3 附加节点 (Attach)

节点名称 说明 源文件
Attach to Player Pawn 附加到玩家 Pawn AttachToPlayerPawnCameraNode.h
Attach to Actor 附加到指定 Actor AttachToActorCameraNode.h
Attach to Actor Group 附加到 Actor 组 AttachToActorGroupCameraNode.h

6.3.1 Attach to Player Pawn 详解

// 源码位置: Public/Nodes/Attach/AttachToPlayerPawnCameraNode.h
UCLASS()
class UAttachToPlayerPawnCameraNode : public UCameraNode
{
    // 骨骼/Socket 附加信息
    UPROPERTY(EditAnywhere, Category=Common)
    FBoneSocketCameraAttachment TargetAttachment;

    // 是否应用玩家控制旋转
    UPROPERTY(EditAnywhere, Category=Common)
    bool bApplyPlayerControlRotation = true;

    // 附加偏移
    UPROPERTY(EditAnywhere, Category=Common)
    FVector3dCameraParameter AttachmentOffset;
};

6.3.2 附加信息结构

// 源码位置: Public/Nodes/Attach/CameraActorAttachmentInfo.h
USTRUCT()
struct FBoneSocketCameraAttachment
{
    GENERATED_BODY()

    // 附加目标类型
    UPROPERTY(EditAnywhere, Category=Common)
    ECameraAttachmentTarget AttachmentTarget;

    // Socket 名称
    UPROPERTY(EditAnywhere, Category=Common)
    FName SocketName;

    // 骨骼名称
    UPROPERTY(EditAnywhere, Category=Common)
    FName BoneName;
};

6.4 构图节点 (Framing)

节点名称 说明 源文件
Dolly Framing 推拉构图 DollyFramingCameraNode.h
Panning Framing 平移构图 PanningFramingCameraNode.h
Camera Framing Zone 取景区域 CameraFramingZone.h

6.4.1 Dolly Framing 详解

// 源码位置: Public/Nodes/Framing/DollyFramingCameraNode.h
UCLASS()
class UDollyFramingCameraNode : public UBaseFramingCameraNode
{
    // 目标演员信息
    UPROPERTY(EditAnywhere, Category=Common)
    FCameraActorTargetInfo TargetInfo;

    // 构图规则
    UPROPERTY(EditAnywhere, Category=Common)
    ECameraFramingMode FramingMode;

    // 目标距离
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter TargetDistance;
};

6.5 输入节点 (Input)

节点名称 说明 源文件
Input 2D 2D 输入处理(Yaw/Pitch) Input2DCameraNode.h
Input 1D 1D 输入处理 Input1DCameraNode.h
Input Axis Binding 2D 2D 输入轴绑定 InputAxisBinding2DCameraNode.h
Auto Rotate Input 2D 自动旋转 2D 输入 AutoRotateInput2DCameraNode.h
Input 2D Slot 相机装备输入槽 CameraRigInput2DSlot.h
Input 1D Slot 相机装备输入槽 CameraRigInput1DSlot.h

6.5.1 Input 2D 详解

// 源码位置: Public/Nodes/Input/Input2DCameraNode.h
UCLASS()
class UInput2DCameraNode : public UCameraNode
{
    // Yaw 旋转速度(度/秒)
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter YawSpeed;

    // Pitch 旋转速度(度/秒)
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter PitchSpeed;

    // Pitch 限制
    UPROPERTY(EditAnywhere, Category=Common)
    FVector2fCameraParameter PitchLimits;

    // 是否反转 Y 轴
    UPROPERTY(EditAnywhere, Category=Common)
    bool bInvertY = false;
};

6.6 抖动节点 (Shakes)

节点名称 说明 源文件
Camera Shake 相机震动(旧版兼容) CameraShakeCameraNode.h
Envelope Shake 包络震动 EnvelopeShakeCameraNode.h
Composite Shake 复合震动 CompositeShakeCameraNode.h
Perlin Noise Location Shake 柏林噪声位置震动 PerlinNoiseLocationShakeCameraNode.h
Perlin Noise Rotation Shake 柏林噪声旋转震动 PerlinNoiseRotationShakeCameraNode.h

6.6.1 包络震动详解

// 源码位置: Public/Nodes/Shakes/EnvelopeShakeCameraNode.h
UCLASS()
class UEnvelopeShakeCameraNode : public UCameraNode
{
    // 震动持续时间
    UPROPERTY(EditAnywhere, Category=Common)
    float Duration = 1.0f;

    // 位置震动幅度
    UPROPERTY(EditAnywhere, Category=Location)
    FVector LocationAmplitude;

    // 位置震动频率
    UPROPERTY(EditAnywhere, Category=Location)
    FVector LocationFrequency;

    // 旋转震动幅度
    UPROPERTY(EditAnywhere, Category=Rotation)
    FRotator RotationAmplitude;

    // 旋转震动频率
    UPROPERTY(EditAnywhere, Category=Rotation)
    FRotator RotationFrequency;

    // 淡入时间
    UPROPERTY(EditAnywhere, Category=Common)
    float BlendInTime = 0.1f;

    // 淡出时间
    UPROPERTY(EditAnywhere, Category=Common)
    float BlendOutTime = 0.2f;
};

6.6.2 震动包络曲线

振幅
1.0 ┤    ●━━━━━━━━━━━━━━━━━━●
    │   ╱                    ╲
    │  ╱                      ╲
0.5 ┤ ╱                        ╲
    │╱                          ╲
0.0 ┤─────────────────────────────► 时间
    │←BlendIn→│←  Sustain  →│←BlendOut→│

6.7 碰撞节点 (Collision)

节点名称 说明 源文件
Collision Push 碰撞推挤检测 CollisionPushCameraNode.h
Occlusion Material 遮挡材质处理 OcclusionMaterialCameraNode.h

6.7.1 Collision Push 详解

// 源码位置: Public/Nodes/Collision/CollisionPushCameraNode.h
UCLASS()
class UCollisionPushCameraNode : public UCameraNode
{
    // 碰撞检测通道
    UPROPERTY(EditAnywhere, Category=Common)
    TEnumAsByte<ECollisionChannel> CollisionChannel = ECC_Camera;

    // 最小推挤距离
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter MinimumDistance;

    // 探针半径
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter ProbeRadius;

    // 探针通道
    UPROPERTY(EditAnywhere, Category=Common)
    TEnumAsByte<ECollisionChannel> ProbeChannel = ECC_Camera;

    // 是否绘制调试线
    UPROPERTY(EditAnywhere, Category=Debug)
    bool bDrawDebugLines = false;
};

6.7.2 碰撞检测流程

1. 从目标点发射射线到相机目标位置
2. 检测射线与碰撞体的相交
3. 如果相交,将相机推到碰撞点前
4. 应用平滑插值避免抖动

目标位置 ●───────────────────────► 相机位置
                    ▲
                 碰撞体

推挤后:
目标位置 ●────────► 新相机位置

7. 扩展开发指南

7.1 自定义相机节点开发

7.1.1 完整示例:跟随延迟节点

Step 1: 创建节点类

// MyFollowDelayCameraNode.h
#pragma once

#include "Core/CameraNode.h"
#include "MyFollowDelayCameraNode.generated.h"

/**
 * 一个自定义节点,实现相机跟随目标时的延迟效果。
 * 相机会在指定时间内平滑地跟随目标位置。
 */
UCLASS(MinimalAPI, meta=(CameraNodeCategories="Common,Transform"))
class UMyFollowDelayCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    UMyFollowDelayCameraNode(const FObjectInitializer& ObjInit);

protected:
    // 返回子节点
    virtual FCameraNodeChildrenView OnGetChildren() override;

    // 构建评估器
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(FCameraNodeEvaluatorBuilder& Builder) const override;

public:
    // 延迟时间(秒)
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter DelayTime;

    // 跟随速度倍数
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter FollowSpeed = 5.0f;

    // 最大跟随距离
    UPROPERTY(EditAnywhere, Category=Common)
    FDoubleCameraParameter MaxDistance = 500.0;

    // 是否在 X/Y 平面跟随
    UPROPERTY(EditAnywhere, Category=Common)
    bool bFollowXY = true;

    // 是否在 Z 轴跟随
    UPROPERTY(EditAnywhere, Category=Common)
    bool bFollowZ = true;
};

Step 2: 创建评估器类

// MyFollowDelayCameraNodeEvaluator.h
#pragma once

#include "Core/CameraNodeEvaluator.h"
#include "MyFollowDelayCameraNodeEvaluator.generated.h"

namespace UE::Cameras
{

class FMyFollowDelayCameraNodeEvaluator : public FCameraNodeEvaluator
{
    UE_DECLARE_CAMERA_NODE_EVALUATOR(GAMEPLAYCAMERAS_API, FMyFollowDelayCameraNodeEvaluator)

public:
    FMyFollowDelayCameraNodeEvaluator();

protected:
    // FCameraNodeEvaluator 接口
    virtual void OnInitialize(const FCameraNodeEvaluatorInitializeParams& Params,
                              FCameraNodeEvaluationResult& OutResult) override;

    virtual void OnRun(const FCameraNodeEvaluationParams& Params,
                       FCameraNodeEvaluationResult& OutResult) override;

    virtual void OnSerialize(const FCameraNodeEvaluatorSerializeParams& Params,
                             FArchive& Ar) override;

private:
    // 历史位置缓冲
    struct FHistoryEntry
    {
        FVector3d Location;
        double Timestamp;
    };
    TArray<FHistoryEntry> LocationHistory;

    // 当前目标位置
    FVector3d CurrentTargetLocation;

    // 当前相机位置(用于插值)
    FVector3d CurrentCameraLocation;

    // 是否已初始化
    bool bInitialized = false;
};

} // namespace UE::Cameras

Step 3: 实现评估器

// MyFollowDelayCameraNodeEvaluator.cpp
#include "MyFollowDelayCameraNodeEvaluator.h"
#include "MyFollowDelayCameraNode.h"

namespace UE::Cameras
{

UE_DEFINE_CAMERA_NODE_EVALUATOR(FMyFollowDelayCameraNodeEvaluator)

FMyFollowDelayCameraNodeEvaluator::FMyFollowDelayCameraNodeEvaluator()
    : CurrentTargetLocation(FVector3d::ZeroVector)
    , CurrentCameraLocation(FVector3d::ZeroVector)
{
}

void FMyFollowDelayCameraNodeEvaluator::OnInitialize(
    const FCameraNodeEvaluatorInitializeParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    bInitialized = false;
    LocationHistory.Empty();
}

void FMyFollowDelayCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    const UMyFollowDelayCameraNode* NodeData = GetCameraNodeAs<UMyFollowDelayCameraNode>();

    // 获取参数值
    const float DelayTime = NodeData->DelayTime.GetValue(OutResult.VariableTable);
    const float FollowSpeed = NodeData->FollowSpeed.GetValue(OutResult.VariableTable);
    const double MaxDistance = NodeData->MaxDistance.GetValue(OutResult.VariableTable);

    // 获取当前相机位置
    const FVector3d CurrentPoseLocation = OutResult.CameraPose.GetLocation();
    const double CurrentTime = FPlatformTime::Seconds();

    // 第一帧初始化
    if (!bInitialized)
    {
        CurrentTargetLocation = CurrentPoseLocation;
        CurrentCameraLocation = CurrentPoseLocation;
        bInitialized = true;
        LocationHistory.Add({CurrentPoseLocation, CurrentTime});
        return;
    }

    // 添加到历史记录
    FHistoryEntry NewEntry;
    NewEntry.Location = CurrentPoseLocation;
    NewEntry.Timestamp = CurrentTime;
    LocationHistory.Add(NewEntry);

    // 清理过期历史
    const double CutoffTime = CurrentTime - DelayTime;
    while (LocationHistory.Num() > 1 && LocationHistory[0].Timestamp < CutoffTime)
    {
        LocationHistory.RemoveAt(0);
    }

    // 计算延迟目标位置(插值)
    FVector3d DelayedTarget = LocationHistory[0].Location;
    for (int32 i = 1; i < LocationHistory.Num(); ++i)
    {
        if (LocationHistory[i].Timestamp <= CutoffTime)
        {
            DelayedTarget = LocationHistory[i].Location;
        }
        else
        {
            // 在两个历史点之间插值
            const double Alpha = (CutoffTime - LocationHistory[i-1].Timestamp) /
                                 (LocationHistory[i].Timestamp - LocationHistory[i-1].Timestamp);
            DelayedTarget = FMath::Lerp(LocationHistory[i-1].Location,
                                        LocationHistory[i].Location, Alpha);
            break;
        }
    }

    // 平滑跟随到延迟目标
    const float DeltaTime = Params.DeltaTime;
    FVector3d NewLocation = CurrentCameraLocation;

    if (NodeData->bFollowXY)
    {
        NewLocation.X = FMath::FInterpTo(CurrentCameraLocation.X, DelayedTarget.X, DeltaTime, FollowSpeed);
        NewLocation.Y = FMath::FInterpTo(CurrentCameraLocation.Y, DelayedTarget.Y, DeltaTime, FollowSpeed);
    }

    if (NodeData->bFollowZ)
    {
        NewLocation.Z = FMath::FInterpTo(CurrentCameraLocation.Z, DelayedTarget.Z, DeltaTime, FollowSpeed);
    }

    // 限制最大距离
    const FVector3d Direction = NewLocation - CurrentPoseLocation;
    const double Distance = Direction.Length();
    if (Distance > MaxDistance)
    {
        NewLocation = CurrentPoseLocation + Direction.GetSafeNormal() * MaxDistance;
    }

    // 更新状态
    CurrentCameraLocation = NewLocation;
    OutResult.CameraPose.SetLocation(NewLocation);
}

void FMyFollowDelayCameraNodeEvaluator::OnSerialize(
    const FCameraNodeEvaluatorSerializeParams& Params,
    FArchive& Ar)
{
    Super::OnSerialize(Params, Ar);

    Ar << CurrentTargetLocation;
    Ar << CurrentCameraLocation;
    Ar << bInitialized;

    // 序列化历史记录
    int32 HistoryCount = LocationHistory.Num();
    Ar << HistoryCount;
    if (Ar.IsLoading())
    {
        LocationHistory.SetNum(HistoryCount);
    }
    for (int32 i = 0; i < HistoryCount; ++i)
    {
        Ar << LocationHistory[i].Location;
        Ar << LocationHistory[i].Timestamp;
    }
}

} // namespace UE::Cameras

Step 4: 实现节点类

// MyFollowDelayCameraNode.cpp
#include "MyFollowDelayCameraNode.h"
#include "MyFollowDelayCameraNodeEvaluator.h"

UMyFollowDelayCameraNode::UMyFollowDelayCameraNode(const FObjectInitializer& ObjInit)
    : Super(ObjInit)
{
    DelayTime.Value = 0.3f;
}

FCameraNodeChildrenView UMyFollowDelayCameraNode::OnGetChildren()
{
    return FCameraNodeChildrenView();
}

FCameraNodeEvaluatorPtr UMyFollowDelayCameraNode::OnBuildEvaluator(
    FCameraNodeEvaluatorBuilder& Builder) const
{
    using namespace UE::Cameras;
    return Builder.BuildEvaluator<FMyFollowDelayCameraNodeEvaluator>();
}

7.1.2 节点开发最佳实践

实践 说明
参数化 使用 F*CameraParameter 类型,支持变量覆盖
状态管理 在评估器中维护状态,支持序列化
性能优化 避免每帧分配内存,预分配缓冲区
调试支持 实现 OnBuildDebugBlocks 提供调试可视化
验证检查 OnPreBuild 中验证参数有效性

7.2 自定义评估服务开发

7.2.1 完整示例:镜头效果服务

// MyLensEffectService.h
#pragma once

#include "Core/CameraEvaluationService.h"
#include "MyLensEffectService.generated.h"

namespace UE::Cameras
{

/**
 * 自定义评估服务:在相机上应用镜头效果(如光晕、色散等)
 */
class FMyLensEffectService : public FCameraEvaluationService
{
    UE_DECLARE_CAMERA_EVALUATION_SERVICE(GAMEPLAYCAMERAS_API, FMyLensEffectService)

public:
    FMyLensEffectService();

    // 设置镜头效果强度
    void SetLensEffectIntensity(float Intensity);

    // 设置色散强度
    void SetChromaticAberration(float Strength);

protected:
    // FCameraEvaluationService 接口
    virtual void OnInitialize(const FCameraEvaluationServiceInitializeParams& Params) override;

    virtual void OnPreUpdate(const FCameraEvaluationServiceUpdateParams& Params,
                             FCameraEvaluationServiceUpdateResult& OutResult) override;

    virtual void OnPostUpdate(const FCameraEvaluationServiceUpdateParams& Params,
                              FCameraEvaluationServiceUpdateResult& OutResult) override;

    virtual void OnRootCameraNodeEvent(const FRootCameraNodeCameraRigEvent& InEvent) override;

private:
    // 效果参数
    float LensFlareIntensity = 0.0f;
    float ChromaticAberrationStrength = 0.0f;

    // 动态更新标志
    bool bNeedsUpdate = false;
};

} // namespace UE::Cameras
// MyLensEffectService.cpp
#include "MyLensEffectService.h"

namespace UE::Cameras
{

UE_DEFINE_CAMERA_EVALUATION_SERVICE(FMyLensEffectService)

FMyLensEffectService::FMyLensEffectService()
{
    // 设置需要接收的回调
    SetEvaluationServiceFlags(
        ECameraEvaluationServiceFlags::NeedsPreUpdate |
        ECameraEvaluationServiceFlags::NeedsPostUpdate |
        ECameraEvaluationServiceFlags::NeedsRootCameraNodeEvents
    );
}

void FMyLensEffectService::OnInitialize(const FCameraEvaluationServiceInitializeParams& Params)
{
    LensFlareIntensity = 0.0f;
    ChromaticAberrationStrength = 0.0f;
    bNeedsUpdate = false;
}

void FMyLensEffectService::SetLensEffectIntensity(float Intensity)
{
    LensFlareIntensity = FMath::Clamp(Intensity, 0.0f, 1.0f);
    bNeedsUpdate = true;
}

void FMyLensEffectService::SetChromaticAberration(float Strength)
{
    ChromaticAberrationStrength = FMath::Clamp(Strength, 0.0f, 1.0f);
    bNeedsUpdate = true;
}

void FMyLensEffectService::OnPreUpdate(
    const FCameraEvaluationServiceUpdateParams& Params,
    FCameraEvaluationServiceUpdateResult& OutResult)
{
    // 在节点评估前执行的逻辑
    // 例如:根据游戏状态自动调整效果强度
}

void FMyLensEffectService::OnPostUpdate(
    const FCameraEvaluationServiceUpdateParams& Params,
    FCameraEvaluationServiceUpdateResult& OutResult)
{
    if (!bNeedsUpdate)
    {
        return;
    }

    // 应用镜头效果到后处理设置
    FPostProcessSettings& PostProcessSettings =
        OutResult.EvaluationResult.PostProcessSettings.GetWriteableObject();

    // 设置色散
    PostProcessSettings.bOverride_SceneFringeIntensity = true;
    PostProcessSettings.SceneFringeIntensity = ChromaticAberrationStrength;

    // 设置光晕(通过 bloom 模拟)
    PostProcessSettings.bOverride_BloomIntensity = true;
    PostProcessSettings.BloomIntensity = LensFlareIntensity;

    bNeedsUpdate = false;
}

void FMyLensEffectService::OnRootCameraNodeEvent(const FRootCameraNodeCameraRigEvent& InEvent)
{
    // 响应相机装备激活/停用事件
    if (InEvent.EventType == ERootCameraNodeCameraRigEventType::Activated)
    {
        // 新相机激活时重置效果
        LensFlareIntensity = 0.0f;
        ChromaticAberrationStrength = 0.0f;
        bNeedsUpdate = true;
    }
}

} // namespace UE::Cameras

7.2.2 服务注册

// 在游戏模块启动时注册服务
void FMyGameModule::StartupModule()
{
    // ...

    // 注册自定义服务
    GetOnCameraSystemEvaluatorCreated().AddLambda([](FCameraSystemEvaluator& Evaluator)
    {
        TSharedRef<FMyLensEffectService> LensEffectService = MakeShared<FMyLensEffectService>();
        Evaluator.RegisterEvaluationService(LensEffectService);
    });
}

7.3 自定义导演开发

7.3.1 完整示例:战斗状态导演

// MyCombatCameraDirector.h
#pragma once

#include "Core/CameraDirector.h"
#include "MyCombatCameraDirector.generated.h"

class UCameraRigAsset;

/**
 * 根据战斗状态切换相机的导演
 */
UCLASS(MinimalAPI)
class UMyCombatCameraDirector : public UCameraDirector
{
    GENERATED_BODY()

public:
    UMyCombatCameraDirector(const FObjectInitializer& ObjInit);

protected:
    // UCameraDirector 接口
    virtual FCameraDirectorEvaluatorPtr OnBuildEvaluator(
        FCameraDirectorEvaluatorBuilder& Builder) const override;

    virtual void OnBuildCameraDirector(UE::Cameras::FCameraBuildLog& BuildLog) override;

    virtual void OnGatherRigUsageInfo(FCameraDirectorRigUsageInfo& UsageInfo) const override;

public:
    // 非战斗状态的相机装备
    UPROPERTY(EditAnywhere, Category=Common)
    TObjectPtr<UCameraRigAsset> ExplorationCameraRig;

    // 战斗状态的相机装备
    UPROPERTY(EditAnywhere, Category=Common)
    TObjectPtr<UCameraRigAsset> CombatCameraRig;

    // 进入战斗的过渡
    UPROPERTY(EditAnywhere, Category=Transitions)
    TObjectPtr<UCameraRigTransition> EnterCombatTransition;

    // 退出战斗的过渡
    UPROPERTY(EditAnywhere, Category=Transitions)
    TObjectPtr<UCameraRigTransition> ExitCombatTransition;
};
// MyCombatCameraDirector.cpp
#include "MyCombatCameraDirector.h"
#include "MyCombatCameraDirectorEvaluator.h"

UMyCombatCameraDirector::UMyCombatCameraDirector(const FObjectInitializer& ObjInit)
    : Super(ObjInit)
{
}

FCameraDirectorEvaluatorPtr UMyCombatCameraDirector::OnBuildEvaluator(
    FCameraDirectorEvaluatorBuilder& Builder) const
{
    using namespace UE::Cameras;
    return Builder.BuildEvaluator<FMyCombatCameraDirectorEvaluator>();
}

void UMyCombatCameraDirector::OnBuildCameraDirector(UE::Cameras::FCameraBuildLog& BuildLog)
{
    // 验证相机装备是否设置
    if (!ExplorationCameraRig)
    {
        BuildLog.AddMessage(EMessageSeverity::Warning,
            TEXT("ExplorationCameraRig is not set"));
    }
    if (!CombatCameraRig)
    {
        BuildLog.AddMessage(EMessageSeverity::Warning,
            TEXT("CombatCameraRig is not set"));
    }
}

void UMyCombatCameraDirector::OnGatherRigUsageInfo(FCameraDirectorRigUsageInfo& UsageInfo) const
{
    if (ExplorationCameraRig)
    {
        UsageInfo.CameraRigs.Add(ExplorationCameraRig);
    }
    if (CombatCameraRig)
    {
        UsageInfo.CameraRigs.Add(CombatCameraRig);
    }
}
// MyCombatCameraDirectorEvaluator.h
#pragma once

#include "Core/CameraDirectorEvaluator.h"

namespace UE::Cameras
{

class FMyCombatCameraDirectorEvaluator : public FCameraDirectorEvaluator
{
    UE_DECLARE_CAMERA_DIRECTOR_EVALUATOR(FMyCombatCameraDirectorEvaluator)

public:
    // 设置战斗状态
    void SetCombatState(bool bInCombat);

protected:
    virtual void OnRun(const FCameraDirectorEvaluateParams& Params,
                       FCameraDirectorEvaluateResult& OutResult) override;

private:
    bool bInCombat = false;
    bool bWasInCombat = false;
};

} // namespace UE::Cameras
// MyCombatCameraDirectorEvaluator.cpp
#include "MyCombatCameraDirectorEvaluator.h"
#include "MyCombatCameraDirector.h"

namespace UE::Cameras
{

UE_DEFINE_CAMERA_DIRECTOR_EVALUATOR(FMyCombatCameraDirectorEvaluator)

void FMyCombatCameraDirectorEvaluator::SetCombatState(bool bInCombatIn)
{
    bInCombat = bInCombatIn;
}

void FMyCombatCameraDirectorEvaluator::OnRun(
    const FCameraDirectorEvaluateParams& Params,
    FCameraDirectorEvaluateResult& OutResult)
{
    const UMyCombatCameraDirector* Director = GetCameraDirectorAs<UMyCombatCameraDirector>();

    // 检测战斗状态变化
    if (bInCombat && !bWasInCombat)
    {
        // 进入战斗 - 请求激活战斗相机
        FCameraDirectorActivationRequest Request;
        Request.CameraRig = Director->CombatCameraRig;
        Request.TransitionOverride = Director->EnterCombatTransition;
        OutResult.ActivationRequests.Add(Request);
    }
    else if (!bInCombat && bWasInCombat)
    {
        // 退出战斗 - 请求激活探索相机
        FCameraDirectorActivationRequest Request;
        Request.CameraRig = Director->ExplorationCameraRig;
        Request.TransitionOverride = Director->ExitCombatTransition;
        OutResult.ActivationRequests.Add(Request);
    }

    bWasInCombat = bInCombat;
}

} // namespace UE::Cameras

8. 实际示例

8.1 示例1:简单的第三人称相机

8.1.1 创建相机装备资产

在编辑器中创建 UCameraRigAsset,设置以下节点结构:

ThirdPersonCameraRig (UCameraRigAsset)
└── RootNode: Sequence
    ├── [0] AttachToPlayerPawn
    │   └── 附加到: Pawn 的 Mesh
    │   └── Socket: Head 或自定义 Socket
    ├── [1] BoomArm
    │   └── BoomOffset: (0, 0, 50)
    │   └── BoomLength: 300
    │   └── InputSlot: Input2D
    ├── [2] CollisionPush
    │   └── CollisionChannel: Camera
    │   └── MinimumDistance: 50
    └── [3] DampenRotation
        └── InterpolationSpeed: 10

8.1.2 代码创建方式

// 创建相机装备
UCameraRigAsset* ThirdPersonRig = NewObject<UCameraRigAsset>();

// 创建 Sequence 节点作为根
UArrayCameraNode* SequenceNode = NewObject<UArrayCameraNode>(ThirdPersonRig);
ThirdPersonRig->RootNode = SequenceNode;

// 添加 AttachToPlayerPawn 节点
UAttachToPlayerPawnCameraNode* AttachNode = NewObject<UAttachToPlayerPawnCameraNode>(SequenceNode);
AttachNode->TargetAttachment.SocketName = FName("Head");
SequenceNode->Children.Add(AttachNode);

// 添加 BoomArm 节点
UBoomArmCameraNode* BoomArmNode = NewObject<UBoomArmCameraNode>(SequenceNode);
BoomArmNode->BoomOffset.Value = FVector(0, 0, 50);
BoomArmNode->BoomLength.Value = 300.0;
SequenceNode->Children.Add(BoomArmNode);

// 添加 Input2D 节点作为 BoomArm 的输入
UInput2DCameraNode* InputNode = NewObject<UInput2DCameraNode>(BoomArmNode);
InputNode->YawSpeed.Value = 90.0f;
InputNode->PitchSpeed.Value = 45.0f;
BoomArmNode->InputSlot = InputNode;

// 添加 CollisionPush 节点
UCollisionPushCameraNode* CollisionNode = NewObject<UCollisionPushCameraNode>(SequenceNode);
CollisionNode->MinimumDistance.Value = 50.0;
SequenceNode->Children.Add(CollisionNode);

// 添加 DampenRotation 节点
UDampenRotationCameraNode* DampenNode = NewObject<UDampenRotationCameraNode>(SequenceNode);
DampenNode->InterpolationSpeed.Value = 10.0f;
SequenceNode->Children.Add(DampenNode);

8.1.3 使用相机装备

// 在 PlayerController 或 Character 中
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();

    // 获取相机组件
    if (UGameplayCameraComponent* CameraComp = FindComponentByClass<UGameplayCameraComponent>())
    {
        // 相机组件会自动使用其 CameraAsset
        // 确保在编辑器中设置了正确的 CameraAsset
    }
}

// 或者通过蓝图函数库激活
#include "GameFramework/ActivateCameraRigFunctions.h"

void AMyCharacter::ActivateThirdPersonCamera()
{
    FActivateCameraRigParams Params;
    Params.CameraRig = ThirdPersonRig;
    Params.Layer = ECameraRigLayer::Main;
    UActivateCameraRigFunctions::ActivateCameraRig(Params);
}

8.2 示例2:相机混合过渡

8.2.1 创建过渡资产

// 创建平滑过渡
UCameraRigTransition* SmoothTransition = NewObject<UCameraRigTransition>();

// 设置混合节点
USmoothBlendCameraNode* BlendNode = NewObject<USmoothBlendCameraNode>(SmoothTransition);
BlendNode->BlendType = ESmoothCameraBlendType::SmootherStep;
BlendNode->Duration.Value = 1.0f;
SmoothTransition->Blend = BlendNode;

// 设置初始朝向
SmoothTransition->bOverrideInitialOrientation = true;
SmoothTransition->InitialOrientation = ECameraRigInitialOrientation::PreviousYawPitch;

8.2.2 运行时切换相机

// 从第三人称切换到第一人称
void AMyCharacter::SwitchToFirstPerson()
{
    // 停用第三人称相机
    FDeactivateCameraRigParams DeactivateParams;
    DeactivateParams.CameraRig = ThirdPersonRig;
    DeactivateParams.Layer = ECameraRigLayer::Main;
    // 注意:Main 层使用 Freeze 而非 Remove
    UActivateCameraRigFunctions::DeactivateCameraRig(DeactivateParams);

    // 激活第一人称相机
    FActivateCameraRigParams ActivateParams;
    ActivateParams.CameraRig = FirstPersonRig;
    ActivateParams.Layer = ECameraRigLayer::Main;
    ActivateParams.TransitionOverride = SmoothTransition;  // 使用自定义过渡
    UActivateCameraRigFunctions::ActivateCameraRig(ActivateParams);
}

8.2.3 过渡条件示例

// 创建带条件的过渡
UCameraRigTransition* ConditionalTransition = NewObject<UCameraRigTransition>();

// 添加条件:只从探索相机切换到战斗相机
UTransitionCondition_CameraRig* FromCondition = NewObject<UTransitionCondition_CameraRig>();
FromCondition->ExpectedCameraRig = ExplorationRig;
ConditionalTransition->Conditions.Add(FromCondition);

// 添加条件:目标必须是战斗相机
UTransitionCondition_CameraRig* ToCondition = NewObject<UTransitionCondition_CameraRig>();
ToCondition->ExpectedCameraRig = CombatRig;
ConditionalTransition->Conditions.Add(ToCondition);

// 设置混合
USmoothBlendCameraNode* Blend = NewObject<USmoothBlendCameraNode>(ConditionalTransition);
Blend->Duration.Value = 0.5f;
ConditionalTransition->Blend = Blend;

8.3 示例3:自定义相机节点

8.3.1 需求:速度响应 FOV 节点

创建一个根据角色移动速度自动调整 FOV 的节点:

// SpeedResponsiveFOVCameraNode.h
UCLASS(MinimalAPI, meta=(CameraNodeCategories="Common,FOV"))
class USpeedResponsiveFOVCameraNode : public UCameraNode
{
    GENERATED_BODY()

public:
    USpeedResponsiveFOVCameraNode(const FObjectInitializer& ObjInit);

protected:
    virtual FCameraNodeEvaluatorPtr OnBuildEvaluator(
        FCameraNodeEvaluatorBuilder& Builder) const override;

public:
    // 最小 FOV(静止时)
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter MinFOV = 75.0f;

    // 最大 FOV(最大速度时)
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter MaxFOV = 90.0f;

    // 触发最大 FOV 的速度阈值
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter MaxSpeed = 1000.0f;

    // 插值速度
    UPROPERTY(EditAnywhere, Category=Common)
    FFloatCameraParameter InterpolationSpeed = 5.0f;
};
// SpeedResponsiveFOVCameraNodeEvaluator.cpp
void FSpeedResponsiveFOVCameraNodeEvaluator::OnRun(
    const FCameraNodeEvaluationParams& Params,
    FCameraNodeEvaluationResult& OutResult)
{
    const USpeedResponsiveFOVCameraNode* NodeData = GetCameraNodeAs<USpeedResponsiveFOVCameraNode>();

    // 获取参数
    const float MinFOV = NodeData->MinFOV.GetValue(OutResult.VariableTable);
    const float MaxFOV = NodeData->MaxFOV.GetValue(OutResult.VariableTable);
    const float MaxSpeed = NodeData->MaxSpeed.GetValue(OutResult.VariableTable);
    const float InterpSpeed = NodeData->InterpolationSpeed.GetValue(OutResult.VariableTable);

    // 获取角色速度(从上下文获取)
    APlayerController* PC = Params.EvaluationContext->GetPlayerController();
    float CurrentSpeed = 0.0f;
    if (APawn* Pawn = PC ? PC->GetPawn() : nullptr)
    {
        CurrentSpeed = Pawn->GetVelocity().Size();
    }

    // 计算目标 FOV
    const float SpeedRatio = FMath::Clamp(CurrentSpeed / MaxSpeed, 0.0f, 1.0f);
    const float TargetFOV = FMath::Lerp(MinFOV, MaxFOV, SpeedRatio);

    // 平滑插值
    CurrentFOV = FMath::FInterpTo(CurrentFOV, TargetFOV, Params.DeltaTime, InterpSpeed);

    // 应用 FOV
    OutResult.CameraPose.FieldOfView = CurrentFOV;
}

8.4 示例4:使用混合栈管理多个相机

8.4.1 多层相机架构

// 游戏中同时运行多个相机层

// === Base Layer ===
// 始终运行的附加效果
FActivateCameraRigParams BaseParams;
BaseParams.CameraRig = AttachToPlayerRig;  // 附加到玩家
BaseParams.Layer = ECameraRigLayer::Base;
UActivateCameraRigFunctions::ActivateCameraRig(BaseParams);

// === Main Layer ===
// 游戏玩法相机(会混合切换)
FActivateCameraRigParams MainParams;
MainParams.CameraRig = ThirdPersonRig;
MainParams.Layer = ECameraRigLayer::Main;
UActivateCameraRigFunctions::ActivateCameraRig(MainParams);

// === Global Layer ===
// 全局效果(震动等)
FActivateCameraRigParams GlobalParams;
GlobalParams.CameraRig = CameraShakeRig;
GlobalParams.Layer = ECameraRigLayer::Global;
UActivateCameraRigFunctions::ActivateCameraRig(GlobalParams);

// === Visual Layer ===
// 后处理效果
FActivateCameraRigParams VisualParams;
VisualParams.CameraRig = PostProcessRig;
VisualParams.Layer = ECameraRigLayer::Visual;
UActivateCameraRigFunctions::ActivateCameraRig(VisualParams);

8.4.2 动态相机切换系统

// MyCameraManager.h
UCLASS()
class UMyCameraManager : public UActorComponent
{
    GENERATED_BODY()

public:
    // 相机模式枚举
    UENUM(BlueprintType)
    enum class ECameraMode : uint8
    {
        Exploration,
        Combat,
        Dialogue,
        Cinematic,
        Death
    };

    // 切换相机模式
    UFUNCTION(BlueprintCallable, Category="Camera")
    void SetCameraMode(ECameraMode NewMode);

    // 获取当前模式
    UFUNCTION(BlueprintPure, Category="Camera")
    ECameraMode GetCurrentMode() const { return CurrentMode; }

protected:
    // 相机资产映射
    UPROPERTY(EditDefaultsOnly, Category="Config")
    TMap<ECameraMode, TSoftObjectPtr<UCameraRigAsset>> CameraRigMap;

    // 过渡资产映射
    UPROPERTY(EditDefaultsOnly, Category="Config")
    TMap<TPair<ECameraMode, ECameraMode>, UCameraRigTransition*> TransitionMap;

private:
    ECameraMode CurrentMode = ECameraMode::Exploration;
    FCameraRigInstanceID CurrentInstanceID;
};

// MyCameraManager.cpp
void UMyCameraManager::SetCameraMode(ECameraMode NewMode)
{
    if (CurrentMode == NewMode)
    {
        return;
    }

    // 获取目标相机装备
    UCameraRigAsset* TargetRig = CameraRigMap[NewMode].LoadSynchronous();
    if (!TargetRig)
    {
        return;
    }

    // 查找过渡
    UCameraRigTransition* Transition = nullptr;
    TPair<ECameraMode, ECameraMode> TransitionKey(CurrentMode, NewMode);
    if (UCameraRigTransition** FoundTransition = TransitionMap.Find(TransitionKey))
    {
        Transition = *FoundTransition;
    }

    // 激活新相机
    FActivateCameraRigParams Params;
    Params.CameraRig = TargetRig;
    Params.Layer = ECameraRigLayer::Main;
    Params.TransitionOverride = Transition;
    CurrentInstanceID = UActivateCameraRigFunctions::ActivateCameraRig(Params);

    CurrentMode = NewMode;
}

8.4.3 相机装备组合示例

// 创建一个组合相机装备:第三人称 + 远程瞄准
UCameraRigAsset* CreateAimingRig()
{
    UCameraRigAsset* Rig = NewObject<UCameraRigAsset>();

    UArrayCameraNode* Sequence = NewObject<UArrayCameraNode>(Rig);
    Rig->RootNode = Sequence;

    // 1. 附加到玩家
    UAttachToPlayerPawnCameraNode* Attach = NewObject<UAttachToPlayerPawnCameraNode>(Sequence);
    Sequence->Children.Add(Attach);

    // 2. 瞄准偏移
    UOffsetCameraNode* AimOffset = NewObject<UOffsetCameraNode>(Sequence);
    AimOffset->LocationOffset.Value = FVector(-100, 50, 0);  // 肩膀位置
    Sequence->Children.Add(AimOffset);

    // 3. 缩放 FOV
    UFieldOfViewCameraNode* FOV = NewObject<UFieldOfViewCameraNode>(Sequence);
    FOV->FieldOfView.Value = 45.0f;  // 缩小 FOV 实现瞄准效果
    Sequence->Children.Add(FOV);

    // 4. 减少输入灵敏度
    UInput2DCameraNode* Input = NewObject<UInput2DCameraNode>(Sequence);
    Input->YawSpeed.Value = 30.0f;
    Input->PitchSpeed.Value = 20.0f;
    Sequence->Children.Add(Input);

    // 5. 碰撞检测
    UCollisionPushCameraNode* Collision = NewObject<UCollisionPushCameraNode>(Sequence);
    Sequence->Children.Add(Collision);

    return Rig;
}

9. 关键文件索引

9.1 核心评估系统

文件 说明
Public/Core/CameraSystemEvaluator.h 相机系统评估器入口
Public/Core/CameraNodeEvaluator.h 节点评估器基类
Public/Core/CameraNodeEvaluatorHierarchy.h 评估器层次结构工具
Public/Core/CameraNode.h 相机节点基类
Public/Core/CameraPose.h 相机姿态数据结构
Public/Core/CameraVariableTable.h 变量表(可混合参数)
Public/Core/CameraContextDataTable.h 上下文数据表(不可混合数据)
Public/Core/CameraEvaluationContext.h 评估上下文
Public/Core/CameraObjectRtti.h 自定义 RTTI 系统
Public/Core/CameraObjectInterface.h 对象接口系统

9.2 混合系统

文件 说明
Public/Core/BlendCameraNode.h 混合节点基类
Public/Core/BlendStackCameraNode.h 混合栈节点基类
Public/Core/PersistentBlendStackCameraNode.h 持久化混合栈
Public/Core/TransientBlendStackCameraNode.h 瞬态混合栈
Public/Core/RootCameraNode.h 根节点基类
Public/Core/DefaultRootCameraNode.h 默认根节点(四层架构)
Public/Core/CameraRigTransition.h 过渡系统
Public/Core/CameraValueInterpolator.h 值插值器

9.3 节点实现

9.3.1 通用节点

Public/Nodes/Common/
├── ArrayCameraNode.h          # Sequence 节点
├── BoomArmCameraNode.h        # 吊臂节点
├── OffsetCameraNode.h         # 偏移节点
├── SetLocationCameraNode.h    # 设置位置
├── SetRotationCameraNode.h    # 设置旋转
├── DampenPositionCameraNode.h # 位置阻尼
├── DampenRotationCameraNode.h # 旋转阻尼
├── FieldOfViewCameraNode.h    # 视场角
├── ClippingPlanesCameraNode.h # 裁剪平面
├── PostProcessCameraNode.h    # 后处理
├── AutoFocusCameraNode.h      # 自动对焦
└── CameraRigCameraNode.h      # 嵌套相机装备

9.3.2 混合节点

Public/Nodes/Blends/
├── SmoothBlendCameraNode.h    # 平滑混合
├── LinearBlendCameraNode.h    # 线性混合
├── PopBlendCameraNode.h       # 立即切换
├── OrbitBlendCameraNode.h     # 轨道混合
└── LocationRotationBlendCameraNode.h

9.3.3 其他节点

Public/Nodes/Attach/
├── AttachToPlayerPawnCameraNode.h
├── AttachToActorCameraNode.h
└── AttachToActorGroupCameraNode.h

Public/Nodes/Input/
├── Input2DCameraNode.h
├── Input1DCameraNode.h
└── AutoRotateInput2DCameraNode.h

Public/Nodes/Shakes/
├── EnvelopeShakeCameraNode.h
├── PerlinNoiseLocationShakeCameraNode.h
└── PerlinNoiseRotationShakeCameraNode.h

Public/Nodes/Framing/
├── DollyFramingCameraNode.h
└── PanningFramingCameraNode.h

Public/Nodes/Collision/
├── CollisionPushCameraNode.h
└── OcclusionMaterialCameraNode.h

9.4 游戏框架集成

文件 说明
Public/GameFramework/GameplayCameraComponent.h 相机组件
Public/GameFramework/GameplayCameraActor.h 相机 Actor
Public/GameFramework/GameplayCameraRigActor.h 相机装备 Actor
Public/GameFramework/ActivateCameraRigFunctions.h 激活函数库
Public/GameFramework/ControllerGameplayCameraEvaluationComponent.h 控制器组件
Public/GameFramework/GameplayCameraSystemComponent.h 系统组件

9.5 服务系统

文件 说明
Public/Core/CameraEvaluationService.h 服务基类
Public/Services/CameraShakeService.h 震动服务
Public/Services/CameraModifierService.h 修饰符服务
Public/Services/CameraParameterSetterService.h 参数设置服务
Public/Services/PlayerControlRotationService.h 控制旋转服务

9.6 导演系统

文件 说明
Public/Core/CameraDirector.h 导演基类
Public/Core/CameraDirectorEvaluator.h 导演评估器
Public/Directors/SingleCameraDirector.h 单一相机导演
Public/Directors/BlueprintCameraDirector.h 蓝图导演
Public/Directors/PriorityQueueCameraDirector.h 优先队列导演
Public/Directors/StateTreeCameraDirector.h 状态树导演

9.7 资产系统

文件 说明
Public/Core/CameraAsset.h 相机资产
Public/Core/CameraRigAsset.h 相机装备资产
Public/Core/CameraShakeAsset.h 震动资产
Public/Core/CameraRigProxyAsset.h 代理资产
Public/Core/CameraVariableAssets.h 变量资产

9.8 调试系统

文件 说明
Public/Debug/CameraDebugBlock.h 调试块基类
Public/Debug/CameraDebugRenderer.h 调试渲染器
Public/Debug/CameraDebugCategories.h 调试分类
Public/Debug/BlendStacksCameraDebugBlock.h 混合栈调试

9.9 构建系统

文件 说明
Public/Build/CameraAssetBuilder.h 资产构建器
Public/Build/CameraRigAssetBuilder.h 装备构建器
Public/Build/CameraBuildLog.h 构建日志
Public/Build/CameraObjectBuildContext.h 构建上下文

附录

A. 术语表

术语 英文 说明
相机资产 Camera Asset 顶层相机配置容器,包含导演、过渡、参数
相机装备 Camera Rig 可复用的相机行为定义,包含节点树
相机节点 Camera Node 最小功能单元,可组合实现复杂行为
评估器 Evaluator 节点的运行时逻辑实现
混合栈 Blend Stack 管理多个相机装备的容器,支持混合过渡
评估上下文 Evaluation Context 提供相机运行环境和数据的容器
导演 Director 控制相机装备激活/停用的逻辑
服务 Service 横切关注点,在评估前后执行
过渡 Transition 定义相机切换时的行为和条件
变量表 Variable Table 可混合的参数存储
上下文数据表 Context Data Table 不可混合的数据存储
相机姿态 Camera Pose 相机的完整状态描述

B. 参考资料

B.1 官方文档

B.2 源码位置

  • 插件根目录: Engine/Plugins/Cameras/GameplayCameras/
  • 公共头文件: Source/GameplayCameras/Public/
  • 私有实现: Source/GameplayCameras/Private/

B.3 相关模块

  • CameraCalibrationCore - 相机校准
  • FilmStock - 胶片效果
  • OpenColorIO - 色彩管理

本文档基于 Unreal Engine 5.6 GameplayCameras 插件源码编写
最后更新: 2026-02-16