UE“反射”概念:
- 反射:UE 通过 UClass/UProperty 等系统在运行时提供类型信息和动态访问能力。
UE 的反射系统是通过 UHT 工具和特定宏实现的代码生成机制。你用 UCLASS 标记类、UPROPERTY 标记变量、UFUNCTION 标记函数,这些宏会被 UHT 识别。
UHT 在编译前扫描这些标记,生成.generated.h 和.cpp 文件,里面包含类的反射注册代码,比如 StaticClass () 函数和 UClass 对象的构造逻辑。
生成的代码会把类信息注册到引擎全局的 GObjectClasses 数组里,让引擎在运行时能动态获取类结构、调用函数或访问属性,这支撑了蓝图交互、垃圾回收等核心功能。
因为 UE 需要在运行时动态处理代码信息。比如蓝图可视化编程,引擎得通过反射知道 C++ 类有哪些函数和变量,才能让蓝图调用它们。
比如你在 C++ 里写了一个角色类,里面有个 UFUNCTION 标记的跳跃函数 Jump ()。没有反射的话,蓝图编辑器根本不知道这个 Jump () 函数存在,因为编译后的机器码里,函数名和参数这些信息都被优化掉了。
有了反射,UHT 会在编译时为这个 Jump () 函数生成反射元数据,包括函数名、参数类型、返回值,以及它属于哪个类。引擎运行时能通过这些元数据,在蓝图编辑器里把 Jump () 函数显示出来,你才能拖拽节点调用它。
如果后续你在 C++ 里给 Jump () 加了一个高度参数,反射系统会自动更新元数据,蓝图里对应的函数节点也会同步显示出新参数,整个过程不需要手动写任何蓝图和 C++ 交互的绑定代码。
回退操作 Command 模式(轻量级):**
1 | 每次操作封装为 ICommand { Do(); Undo(); } |
2. Snapshot 模式(适用于复杂场景):
1 | 操作前序列化整个对象状态的快照 |
实际项目中的混合方案:
- 简单属性修改 → Command 模式(记录 oldValue/newValue)
- 复杂操作(节点图变更、场景编辑)→ Snapshot 或 Diff 模式
- 合并机制:连续同类操作合并(如拖拽 Slider 时合并为一条记录)
UE智能指针对比表
| 指针类型 | 管理对象 | 所有权 | 核心作用 | 适用场景 |
|---|---|---|---|---|
| TObjectPtr | UObject派生类 | 共享 | 安全访问UObject,自动参与垃圾回收 | 替代传统UPROPERTY指针,日常UObject引用 |
| TWeakObjectPtr | UObject派生类 | 无 | 弱引用UObject,不阻止回收 | 避免循环引用,临时访问可能被销毁的UObject |
| TSoftObjectPtr | UObject派生类 | 无 | 软引用UObject,支持资源异步加载 | 引用可能未加载的资源,如关卡外的模型、纹理 |
| TSharedPtr | 非UObject类型 | 共享 | 通过引用计数管理生命周期 | 需要多持有者共享非UObject资源 |
| TUniquePtr | 非UObject类型 | 独占 | 唯一拥有对象,不可复制 | 管理无需共享的非UObject资源,如自定义数据结构 |
| TWeakPtr | 非UObject类型 | 无 | 弱引用TSharedPtr,不增加引用计数 | 配合TSharedPtr避免循环引用 |
关键区别说明
管理对象边界:前三种严格用于UObject派生类,依赖UE垃圾回收系统;后三种用于非UObject类型,靠手动内存管理机制。
UObject指针细分:
- TObjectPtr是强引用,会让UObject保持存活,是日常开发的首选。
- TWeakObjectPtr是弱引用,当UObject被标记为回收时,指针会自动置空,常用在UI控件引用角色对象这类场景。
- TSoftObjectPtr存储的是资源路径而非直接内存地址,对象未加载时可异步加载,适合开放世界游戏引用远处的资源。
- 非UObject指针细分:
- TSharedPtr通过引用计数共享对象,当引用计数为0时自动释放内存,但需注意手动避免循环引用。
- TUniquePtr是独占式指针,不允许复制,只能通过移动语义转移所有权,性能开销最小。
- TWeakPtr需要绑定到TSharedPtr使用,当TSharedPtr释放对象后,TWeakPtr会自动失效,解决循环引用问题。
ECS 架构是什么?和传统 OOP 有什么区别?
| OOP | ECS | |
|---|---|---|
| 数据布局 | 对象分散在堆上 | Component 连续内存排列 |
| 缓存友好性 | 差(指针跳转) | 好(数据局部性) |
| 逻辑组织 | 方法绑定在类上 | System 独立遍历 Component |
| 组合性 | 需要多重继承/组合模式 | 天然组合(挂 Component 即可) |
| 其实ECS节省的是cpu去查找的时间。 |
核心概念:
- Entity:ID 标识,不存数据
- Component:纯数据(Position, Velocity, Health…)
- System:纯逻辑(MovementSystem 遍历所有 Position+Velocity 组件)
核心区别:OOP 以对象为核心,数据与逻辑封装在类中,易形成复杂继承树;ECS 将数据与逻辑分离,实体为组件容器,系统批量处理同类组件,数据连续存储提升缓存效率,支持动态组合与并行计算。
UE5 Mass 系统案例:作为 ECS 实现,Mass 用 “片段” 存储实体数据,“处理器” 统一处理逻辑。如《黑客帝国》Demo 中的万人级 crowd 模拟,通过将角色位置、速度等数据打包连续存储,移动处理器可批量更新所有角色坐标,性能远超传统 Actor 方案。
堆Stack 栈heap
- 堆(Heap):动态分配内存,大小不固定,生命周期由程序员控制,访问速度较慢,适合存储大对象或需要在运行时确定大小的数据。(没有固定的存取顺序)
- 栈(Stack):自动分配内存,大小固定,生命周期由函数调用控制,访问速度快,适合存储局部变量和函数参数。(有固定的存取顺序,后进先出)
Function Calling 的原理是什么?你在项目中怎么用的?
原理: LLM 不直接执行函数,而是 输出结构化的函数调用意图(函数名 + 参数),由宿主程序解析并执行。
RAG 是什么?你是怎么实现的?
RAG(Retrieval-Augmented Generation) = 先检索相关文档,再让 LLM 基于检索结果回答。
ControlNet 是什么?它解决了什么问题?
参考答案:
ControlNet 为预训练 Diffusion Model 添加 空间控制能力。
解决的问题: 原始 Text-to-Image 无法精确控制生成图像的构图、姿态、边缘等空间结构。
原理:
- 在 Stable Diffusion 的 U-Net 每个 Block 上添加一个并行的 “Zero Convolution” 分支
- 输入额外的条件图(边缘检测/Canny、深度图、姿态/OpenPose、法线贴图等)
- 训练时只训练 ControlNet 分支,冻结原始模型
常见 ControlNet 类型:
- Canny Edge:控制轮廓
- Depth:控制深度结构
- OpenPose:控制人物姿态
- Segment:控制区域分割
- Scribble:控制草图
LoRA 是什么?为什么它很受欢迎?
LoRA(Low-Rank Adaptation) 是一种参数高效微调方法。
LoRA 是一种参数高效的大模型微调技术,核心是冻结原模型权重,仅训练少量低秩矩阵来模拟任务适配所需的参数更新。它参数量仅为全量微调的 0.1%-1%,大幅降低显存占用和训练成本,且推理时可合并权重无额外延迟。
在游戏领域,能快速微调图生图模型生成风格统一的角色装备、场景素材,或微调对话模型让 NPC 生成符合设定的自然台词,适配小团队高效开发需求。
MVC、MVP、MVVM 的区别是什么?
| 模式 | 组件职责 | 组件关系 | 优缺点 |
|---|---|---|---|
| MVC | Model(数据) View(界面) Controller(逻辑) |
Controller 直接操作 Model 和 View | 简单直观,适合小型项目;Controller 可能变得臃肿 |
| MVP | Model(数据) View(界面) Presenter(逻辑) |
Presenter 直接操作 Model,间接更新 View | Presenter 可测试性强;View 依赖 Presenter,增加耦合 |
| MVVM | Model(数据) View(界面) ViewModel(逻辑) |
ViewModel 直接操作 Model,通过数据绑定更新 View | 双向绑定简化 UI 更新;学习曲线较陡峭,可能引入性能问题 |
- MVP的Preseter和MVVM的ViewModel在职责上非常相似,都是处理业务逻辑和数据交互的中介,但MVVM通过数据绑定机制让ViewModel直接更新View,减少了Presenter中大量的UI更新代码,使得代码更简洁、可测试性更强。MVVM适合复杂UI交互较多的项目,而MVP则更适合简单UI或需要严格分离测试的场景。
GPU 渲染流水线的完整阶段?
参考答案:
GPU 渲染管线(Rendering Pipeline)是 GPU 执行图形渲染的完整流程:
应用阶段(CPU 侧):
1 | 1. 应用阶段(Application Stage) |
几何阶段(GPU 顶点着色器):
1 | 2. 顶点着色器(Vertex Shader) |
光栅化阶段(Rasterization):
1 | 5. 图元装配 & 裁剪 |
片段/像素阶段:
1 | 8. 片段着色器(Fragment / Pixel Shader) |