知识框架

1. 硬件与图形 API 基础

  • Vulkan、Metal、DirectX 定位与 UE5 的 RHI 抽象

  • Vulkan 和 Metal:

    它们是图形驱动 API(接口)。你可以把它们理解为游戏引擎与显卡沟通的“语言”。

    • Vulkan: 由 Khronos 组织开发,主要用于 Android 和 PC。它非常底层,能让开发者直接控制 GPU。

    • Metal: 由 Apple 开发,专门用于 iOS/macOS。它的执行效率极高,是苹果设备的标配。

    • DirectX 是微软 Windows 专属(部分支持 Xbox),Vulkan 是跨平台(Windows、Linux、Android、Switch 等)。

    • 特性 DirectX 11 (传统派) DirectX 12 (现代派)
      核心理念 高度自动化,“保姆级”封装,易于开发但性能上限受限 底层的“专家模式”,将硬件控制权充分交给开发者,性能潜力巨大
      CPU利用率 主要依赖单线程,对多核CPU利用不充分 原生支持多线程,能让所有CPU核心高效工作,减轻瓶颈
      性能表现 对不同硬件的兼容性更稳定 在优化得当的情况下,游戏帧率可比DX11提升10%-20%
      支持平台 Windows 7及更高版本 Windows 10及更高版本(不支持Windows 7)
      前沿技术 基础 支持光线追踪(DirectX Raytracing,让光影更真实)、可变速率着色等画质提升技术
      开发难度 较低 较高,需要开发者具备更深的硬件知识
    • RHI (Render Hardware Interface):

      它是 UE 的渲染硬件接口层

      • 作用: 它是“翻译官”。UE 写了一套通用的渲染命令,RHI 负责把这些命令翻译成 Vulkan、Metal 或 DirectX 能够识别的指令。

      • 硬件对应: 它运行在 CPU 上,但控制着 GPU 的行为。

  • RHI 与性能监控工具(GPU Profiler、Unreal Insights)

  • 设备类型 目标帧率 (FPS) 内存占用 建议性能目标
    高端 PC 120+ 不限 开启全动态光影 (Lumen),显存 8GB+
    安卓 (高端) 60 2GB 左右 烘焙光照,使用 RVT,材质指令 < 200
    安卓 (低端) 30 800MB 禁用阴影,贴图最大 1024,材质指令 < 100

    如何设定:

  • 建立 Device Profiles: 在 UE 中针对 Android_LowAndroid_High 设置不同的纹理上限和渲染等级。

  • 性能抓帧: 在目标手机上运行,观察 GPU Time。如果 GPU Time > 33ms,那说明你的画面必须降级(30 帧都稳不住)。

  • Stat Unit 解读

    指标 你的数值 解读
    Frame 21.54ms (浮动28-30ms) 帧耗时。移动端目标通常是30 FPS(33.3ms)或60 FPS(16.67ms)。
    Game 5.69ms 游戏线程耗时(处理蓝图、物理、AI等)。<5ms表示良好,<10ms可接受。
    Draw 7.64ms 渲染线程(收集绘制命令)耗时。
    RHI 7.30ms RHI线程(将渲染命令翻译为图形API调用)耗时。
    GPU Time 20.76ms GPU实际渲染耗时。(如果目标是60 FPS,则超标;如果目标是30 FPS,则处于临界)。
    Mem 763.56MB 总内存占用。对移动端偏高,需关注纹理/渲染目标内存。
    RenderRes 91.2% (1459x657) 渲染分辨率约为屏幕分辨率的91%,常见且合理。
    Draws 303 绘制调用数(CPU提交给GPU的绘制命令)。移动端推荐<500。
    Prims 3930.2K 每帧绘制的三角形数量约393万。对于移动端,这个值偏高(通常建议<100万),需优化模型面数或LOD。
  • RHI (Rendering Hardware Interface) 是引擎与显卡之间的桥梁。

  • 指令: 在控制台(~键)输入 stat RHI

  • 关键数值:

    • Draw Calls: 显卡要画多少次。移动端建议控制在 200-500 以内。

    • Triangles / Primitives: 画面里三角形的总数。

    • Total GPU Memory: 显存占用。

  • 意义: 如果 Draw Calls 极高,说明你模型没合批;如果 Primitives 极高,说明你没做 LOD。

  • CPU-GPU 协作:几何图元、Draw Call 概念

  • 内存架构:RAM vs VRAM,Cache 层次,数据流转路径

  • 内存(RAM)与显存(VRAM)

    在 PC 上,内存和显存是分开的。但在手机上,它们是共用一块内存芯片的。

  • PC 架构: 内存(RAM)在主板上,存逻辑;显存(VRAM)在显卡上,存贴图。

  • 移动端架构(SoC): 统一内存架构 (Unified Memory)

    • CPU 和 GPU 共用一块物理内存条。

    • 如果你说“贴图占了 2GB”,那这 2GB 就从手机的总 8GB 内存里划走了。这意味着如果贴图过载,系统会直接杀掉游戏进程(崩溃)。

  • 计算公式:

    一个未经压缩的贴图大小为:

    Width x Height x 4 bytes (RGBA)}

    例如:一张 2K 贴图 (2048x2048) 约为 16MB

  • 内存缓存 (Memory Cache)

  • L1 / L2 / L3 Cache

    Cache(缓存) 是为了解决 “CPU 算得太快,而内存搬运太慢” 的问题。

  • L1 (Level 1): 最靠近核心,速度最快(接近 CPU 频率),但容量极小(几十 KB)。像你手里的笔

  • L2 (Level 2): 速度稍慢,容量稍大(几百 KB 到几 MB)。像你桌上的笔记本

  • L3 (Level 3): 所有核心共享,容量最大(几十 MB),速度最慢(但仍比内存快得多)。像你书架上的字典

  • 内存 (RAM):楼下的图书馆。如果 CPU 去内存拿数据,它得停下来等几百个时钟周期,表现出来的就是游戏卡顿。

2. 渲染管线与资产流转

  • 完整渲染管线过程(顶点→像素→帧缓冲)

  • 应用阶段 (CPU): 决定谁该被画出来。计算角色的动作、碰撞、UI,最后打包成指令发给 RHI。

  • 几何阶段 (GPU):

    • 顶点着色器 (VS): 把模型的 3D 坐标转换成屏幕上的 2D 坐标。局部空间 →世界空间: 物体在地图里的位置。世界空间→观察空间: 物体相对于相机的位置。观察空间 →裁剪空间: 利用投影矩阵(Projection Matrix),将 3D 坐标投影到 2D 屏幕区域。

    • 裁剪与剔除:  视锥体剔除 (Frustum Culling): CPU 判断物体是否在相机镜头里。不在的直接“砍掉”,不发 Draw Call。  遮挡剔除 (Occlusion Culling): 判断物体是否被前面的大墙挡住了。  背面剔除 (Backface Culling): GPU 在渲染时发现三角形的背面朝着相机,直接不画。。

  • 光栅化阶段 (GPU): 把三角形连成的几何图形转换成成千上万个“像素点”。原理: GPU 会扫描屏幕上的每一个像素,判断这个像素中心点是否落在某个三角形内部。如果在内部,就给这个像素打个“标签”,准备涂颜色。

  • 像素阶段 (GPU):

    • 像素着色器 (PS): 计算每个像素点应该是什么颜色。这就是你 872 条指令材质干活的地方。这是计算颜色的步骤。它根据你材质里的逻辑(贴图、光照、If 判断、Power 运算),算出光栅化产生的每一个像素点最终应该是红的还是绿的。

  • 输出合并: 把透明度混合、深度测试做好,最后把这一帧的画面塞进显示器。

  • 原理: GPU 会扫描屏幕上的每一个像素,判断这个像素中心点是否落在某个三角形内部。如果在内部,就给这个像素打个“标签”,准备涂颜色。

  • UV 坐标与纹理映射

  • UV 坐标不是世界坐标。

  • 定义: UV 是模型表面上的 2D 坐标系统 ($u, v \in [0, 1]$)。你可以把它想象成把一个纸箱子拆开铺平后的平面坐标。

  • 关系:

    • 顶点: 模型上的一个点(3D)。

    • UV: 对应这个顶点在贴图上的哪个位置(2D)。

  • 顶点动画与 UV:

    • 顶点动画改变的是顶点的 3D 位置(比如风吹动树叶)。

    • UV 通常是不动的。即使顶点动了,它依然读取贴图上那个点的颜色。

  • 资产从硬盘到显存的完整路径(.uasset → 内存 → VRAM)

  • 渲染管线资产流转图(从硬盘到显示器)

  • 硬盘 (SSD): 存储 .uasset 原始数据。

  • 内存 (RAM): 当你加载关卡,CPU 把模型结构、逻辑变量调入内存。

  • 显存 (VRAM): 贴图、顶点数据被推入显存,等待 GPU 召唤。

  • 寄存器/缓存: GPU 运算过程中的临时数据。

  • 实时渲染与离线渲染的区别

  • 实时渲染: 玩家在安卓手机上操作,GPU 每秒计算 30-60 帧。这时 Draw Call 极度重要,因为 CPU 必须实时告诉 GPU 画什么。Draw Call 高了,手机就卡成幻灯片。

  • 离线渲染(视频):电影大片。一帧算 1 小时,极致精度。 只有当你打算把游戏内容做成一段宣传片/开场动画时,才叫离线渲染。渲染完输出的是视频格式。

  • 为什么安卓端不用离线渲染? 因为视频没有交互。如果玩家能控制角色走动,那就必须是实时渲染。

  • 性能提升: 降低 Draw Call 提升的是 CPU 的分发效率,而不是离线渲染的内存。

  • UE 实现离线渲染: 使用 Movie Render Queue (MRQ)

  • 操作: Window -> Cinematics -> Movie Render Queue。在设置里开启 High Quality ADISON 采样,能把场景渲染成真正的电影画质。

ue管线的可编程阶段与固定阶段

1. 可编程阶段 (Programmable Stages)

这些阶段允许开发者编写 HLSL (High-Level Shading Language) 代码。在 UE 中,你通常通过材质编辑器 (Material Editor) 的连线逻辑来间接控制这些阶段。

  • 顶点着色器 (Vertex Shader, VS):

    • 功能: 处理每一个顶点的位置、法线和切线。

    • UE 中的应用: 材质节点中的 World Position Offset (WPO)。你可以通过它实现旗帜飘动、植被摆动或复杂的顶点动画。

  • 像素/片元着色器 (Pixel/Fragment Shader, PS):

    • 功能: 决定屏幕上每个像素的最终颜色。

    • UE 中的应用: 材质编辑器的大部分逻辑(Base Color, Roughness, Normal, Metallic 等)。这是计算光照、纹理采样和颜色混合的核心区域。

  • 计算着色器 (Compute Shader, CS):

    • 功能: 独立于常规渲染流程的高性能并行计算。

    • UE 中的应用: Niagara 粒子系统的复杂物理模拟、虚拟阴影映射 (VSM) 的剔除、以及后期处理中的某些高级特效。


2. 固定功能阶段 (Fixed-Function Stages)

这些是由 GPU 硬件直接完成的物理过程。虽然你可以通过渲染状态(如深度测试开关)来配置它们,但你不能编写逻辑代码来改变它们的工作方式。

  • 输入装配 (Input Assembler, IA):

    • 功能: 读取缓冲区中的顶点数据(位置、UV、颜色)并组合成几何图元(三角形、线段)。

  • 光栅化 (Rasterization):

    • 功能: 将 3D 空间中的几何体转换为 2D 屏幕上的像素点(片元)。

    • 注意: 这是渲染流水线中最典型的“固定”阶段,硬件会自动判断哪些像素被三角形覆盖。

  • 深度测试与模板测试 (Early-Z / Stencil Test):

    • 功能: 决定一个像素是否应该被遮挡。

    • UE 优化: UE 频繁使用 Early-Z Pass,在执行昂贵的像素着色器之前先剔除被遮挡的像素,这属于硬件级的优化。

    • 问题:传统深度测试在像素着色器之后进行。那些最终被挡住的像素仍然跑完了昂贵的像素着色器,浪费性能。

      Early-Z:在像素着色器之前就执行深度测试,直接丢掉会被遮挡的像素。

      特性 传统深度测试 Early-Z
      执行时机 像素着色器之后 像素着色器之前
      能否丢弃被挡像素 可以,但已浪费着色器计算 可以,并且避免无用的着色
      性能 低(浪费) 高(节约)
      限制 如果像素着色器修改深度值(如discard、深度写入),Early-Z失效
  • 输出合并 (Output Merger):

    • 功能: 将计算出的像素颜色与当前的渲染目标(RenderTarget)进行混合,并处理 Alpha Blending(半透明混合)。


3. UE 特有的逻辑划分

由于 UE 是一套高度抽象的引擎,它在标准管线之上增加了自己的逻辑层:

阶段 类型 描述
Nanite 虚拟几何体 半可编程 使用计算着色器 (CS) 代替了传统的光栅化逻辑,实现了极高面数的渲染。
Material Instance 配置化 通过参数化控制可编程阶段,而无需重新编译 Shader。
RHI (Rendering Hardware Interface) 中间层 负责将 UE 的渲染指令翻译给具体的硬件 API(如 DX12 变为硬件指令)。
  • 顶点 / 像素着色器中的运算
    Shader 里凡是用到 ScalarParameter 的地方,实际是一个 uniform float
    改变实例里的数值 → 更新 uniform → 着色器内部的乘法、Lerp、分支条件等计算结果发生变化,但指令序列不变。

  • 纹理采样
    TextureSampleParameter 允许实例换一张贴图 → 只需绑定不同的 SRV(Shader Resource View),同样不触发重编译。

  • 静态开关参数(Static Switch)—— 特殊情况
    这种参数会真正改变 Shader 代码(比如去掉一大段指令)。
    但 UE 会为每个开关组合预编译出独立的 Shader 变体
    实例选择不同的开关状态时,只是切换到另一个已编译好的变体,不会发生运行时的实时编译

3. 纹理与材质(TA 的重头戏)

3.1 纹理核心概念

  • Mipmap、纹理术语(Albedo、Normal、Roughness 等)
  • Mipmap (多级渐远纹理)
  • 开启方法: 双击贴图进入编辑器,在右侧搜索 Mip Gen Settings,通常选 FromTextureGroup 即可。

  • 原理: 引擎会预先生成不同尺寸的缩略图。远处的物体用小图,既省显存又能减少画面闪烁(走样)。

  • Mipmap 是一组预计算的纹理序列,每一级的分辨率都是前一级的 1/2。比如一张 1024x1024 的图,它的 Mip 链包含 512、256、128……直到 1x1。

  • 工作原理: 当 GPU 渲染物体时,它会计算该物体在屏幕上占据了多少个像素(Pixel)。如果一个远处的油漆桶在屏幕上只占 10 个像素,GPU 就不会去读取那张 1024 像素的大图(那太浪费带宽了),而是直接抓取 Mip 链中对应大小的小图(比如 16x16)。

  • 为什么要用它?

    1. 性能(带宽): 显卡读取的数据变少了,总线压力变小。

    2. 抗锯齿(Moiré Patterns): 如果没有 Mipmap,当高分辨率纹理在远距离渲染时,像素点会跳跃,产生闪烁和类似“摩尔纹”的噪点。

  • 空间换时间: 开启 Mipmap 会增加约 33.3% 的磁盘和显存占用。但在移动端,这 33% 的空间支出是绝对超值的,因为它换回了帧率的稳定。

  • PBR纹理术语速查表
    术语 通俗理解 黑/白代表什么 常见后缀
    Albedo(固有色) 物体本来的颜色,不受光照影响。就像一张彩色照片,没有阴影和高光。 无黑白含义,就是RGB颜色 _D , _BaseColor , _Albedo
    Normal(法线贴图) 欺骗眼睛的“假凹凸”。通过改变表面光线反射角度,让低模看起来有高模的细节(如砖缝、铆钉)。 法线向量存在纹理中,呈蓝紫色(非黑白) _N , _Normal
    Roughness(粗糙度) 表面是光滑还是粗糙。反光越糊、越分散 → 表面越粗糙。 白=粗糙(磨砂、石头)
    黑=光滑(镜子、金属)
    _R , _Roughness
    Metallic(金属度) 区分金属与非金属。金属反光带自身颜色,非金属反光为白色。 白=金属(铁、金)
    黑=非金属(木头、塑料)
    _M , _Metallic
    AO(环境光遮蔽) 预制的“暗角”,模拟缝隙、角落中光线难以进入产生的阴影,增加立体感。 白=无遮挡(开放区域)
    黑=完全遮挡(缝隙深处)
    _AO , _Occlusion
    Height / Displacement 真正的凹凸,会移动顶点位置或视差偏移,产生立体感(代价大)。 白=凸起
    黑=凹陷
    _H , _Height , _Disp
    Emissive(自发光) 物体自己发光,不受场景光照影响,甚至能照亮周围。 无黑白含义,就是RGB颜色(亮度可超出1) _E , _Emissive

    📌 一句话记住它们的作用关系

    Albedo 给颜色,Normal 骗凹凸,Roughness 定光滑,Metallic 分金属,AO 加暗角。

  • 法线贴图格式:DX(Y-) vs OpenGL(Y+)
  • DX (DirectX): 绿通道反向。

  • GL (OpenGL): 正常。

  • 识别: 如果你发现法线在场景里看起来凹凸反了(灯光照上去怪怪的),双击贴图,勾选 Flip Green Channel 就能解决。

  • 贴图优劣标准与跨平台分配策略

  • 贴图优良差的标准:
  • 优: 尺寸为 2 的幂次方(如 512, 1024);使用了压缩格式(PC 用 BC7,安卓用 ASTC,iOS 用 PVRTC);采样器数量少。

  • 差: 奇数尺寸;使用了过多的 Alpha 通道(透明);未开启 Mipmaps(导致远处闪烁且浪费性能)。

  • Project Settings -> Device Profiles 中。

  • 你可以为 Android_High 设置贴图最大分辨率为 2048,为 Android_Low 设置为 512。

  • 引擎会自动根据设备性能,在加载时对贴图进行截断(Clamp)。

  • 纹理资源: 硬盘上的 .png / .tga 文件。

  • 纹理对象: 贴图本身作为一种参数被传递(常用于材质函数内部)。

  • 纹理采样: 一个动作。GPU 去贴图里查“这个点的颜色是什么”。

3.2 材质逻辑与性能

  • 材质域(Material Domain)Surface、Deferred Decal、Post Process 等,决定材质节点链的最终用途

  • 材质域告诉 GPU 这个着色器应该在渲染管线的哪一步运行。

  • Surface (表面): 默认模式。用于所有实型物体(草、石头、人)。受光照影响。

  • Deferred Decal (延迟贴花): 像贴纸一样贴在别的物体上。

    • 注意: 贴花过多会导致 Overdraw。层叠多了会导致材质复杂度变白。

  • Post Process (后处理):它在整个画面渲染完后,对屏幕像素进行二次计算(如全屏雪花、色调调节)

  • 混合模式(Blend Mode)

    • Opaque(不透明,性能最优)

    • Masked(带透明裁剪,Alpha Test 开销)

    • Translucent(半透明,开销最大,涉及排序和 Overdraw)

  • 材质三兄弟(MF / MID / MPC)

    • 材质函数(MF):黑盒封装,复用节点网络

    • 动态材质实例(MID):运行时修改参数,避免材质编译

    • 材质参数集(MPC):全局控制多材质参数

    • 概念 类比 作用范围 性能/特性
      Material Parameter Collection (MPC) 广播站 全局。修改一个值,场景内所有引用它的材质都会同步改变。 极高。CPU 只发一次指令,GPU 批量更新。适合做雨雪、昼夜、全局风力。
      Dynamic Material Instance (DMI) 私人电话 实例级。每个物体可以有独特的值(如:这个怪血多,那个怪血少)。 中等。每个物体都要单独通信。必须在蓝图/C++ 中创建并赋值。
      材质参数 (Scalar/Vector Param) 变量名 基础单元。它是 MPC 或 DMI 里被修改的具体那个“名字”。 只是一个槽位,本身不决定性能。
  • Alpha 透明性能开销与通道打包技术

  • 具体含义: 不只是半透明。

  • Masked (遮罩): 比如树叶,虽然不是透明,但有镂空。这会导致 Overdraw (过度绘制),即显卡在同一个像素点上画了好几次,性能消耗极大。

  • 移动端准则: 能用几何体切出来的形状,别用 Alpha 贴图抠。

  • Alpha 通道与性能:隐藏的“隐形杀手”

    A. Alpha 通道占用的性能逻辑

    纹理在内存中的存储是按通道算的:

  • RGB 纹理: 占用 3 个 8-bit 通道(24 位/像素)。

  • RGBA 纹理: 占用 4 个 8-bit 通道(32 位/像素)。 结论: 只要你带了 Alpha 通道,显存占用直接增加 33%。在移动端带宽极其有限的情况下,这会导致 GPU 读取纹理变慢。

  • B. 合并 Alpha 到 BaseColor 的利弊

    Wit 的友情纠正: 不要单纯为了“减少纹理数量”就把所有东西往一张 4K 贴图里塞。合并 Alpha 后的 BaseColor 如果变成了 4K,而你原本的 Alpha 只需要 512 的清晰度,那你反而浪费了大量的内存空间。匹配分辨率优先级 才是高手的基操。

    C. 终极优化建议:通道打包 (Channel Packing)

  • Masked 材质在移动端的优化方法

    Masked 材质开销较大,可以做以下优化:

  • 改用 Opaque + 模型裁剪:如果物体形状固定,将 Mask 效果直接做进模型(几何体裁剪)。

  • 减少 Overdraw:控制 Mask 区域不要过于细碎。

  • 降低分辨率:降低 Mask 纹理分辨率,并使用高质量采样。

  • 针对移动端使用 Simple Shader:避免复杂的光照计算。

  • 匹配分辨率优先级

    这是一个美术资源管理的“潜规则”:

    在职业开发中,我们通常不只是合并 Alpha。我们会进行 RGBA 全填充

  • 逻辑: 并不是所有贴图都要一样大。

  • 优先级排序:

    1. 最高(4K/2K): 玩家视线正前方的地板、主角的脸、武器。

    2. 中等(1K/512): 远处的墙壁、大型装饰物。

    3. 最低(256/128): 高处的电线杆、地面掉落的小碎石、远景的楼房。

  • 匹配原则: 如果一个物体在屏幕上看起来只有 10 像素宽,你给它 4K 贴图就是犯罪。你应该根据物体在游戏中的平均占据大小来决定其贴图分辨率。

  • 黑盒思维:在材质函数、蓝图类中封装复杂逻辑,只暴露必要输入/输出

3.3 Lumen 全局光照(项目设置与性能影响)

项目设置:Lumen 详解

Lumen 是 UE5 的动态全局光照系统。在移动端,目前的建议是:全部关闭。 手机跑不动 Lumen。

  • 项目设置:

    • 软件光线追踪 (Software Ray Tracing): 使用网格体距离场(Mesh Distance Fields)。消耗中等,不支持复杂的几何体变形。

    • 硬件光线追踪 (Hardware Ray Tracing): 需要 RTX 显卡。支持 Nanite 细节,精度极高,消耗巨大。

  • 性能影响: Lumen 每帧都会在后台更新巨大的“场景缓存(Scene Cache)”。

  • 移动端警告: Lumen 不支持移动端。 如果你在项目中开启了 Lumen,而又强行在移动预览模式下运行,引擎可能会因为无法回退到静态光照而产生巨大的性能冗余。

    • 建议: 移动端请将全局光照设为 NoneScreen Space,并靠 烘焙 Lightmaps 解决光影。

UE5.7中的lumen设置分别对应以下的作用:

  • 硬件光线追踪: 利用显卡专门的 RT 核计算光线,效果最好但最吃资源。

  • 光线光照模式: 决定光线如何反弹(表面缓存效率高,命中光照更精确)。

  • 高质量半透明反射: 让玻璃等透明物体能反射出场景。

  • 屏幕追踪源 (Screen Tracing): 利用屏幕上已有的像素做近似光影。

  • 场景颜色: 影响全局光照的色彩反馈。

4. 引擎核心系统(UE5 特有)

  • 蓝图逻辑:变量、函数、宏、事件;蓝图接口(BPI)

  • 蓝图逻辑与变量的作用域执行堆栈区别。

  • A. 变量 (Variables) 的高级控制

  • Instance Editable (小眼睛开启): 勾选后,变量会暴露在关卡编辑器中。这意味着你可以在不打开蓝图的情况下,为场景中不同的“路灯”设置不同的颜色。

  • Expose on Spawn: 非常实用。当你用 SpawnActorFromClass 生成物体时,这个变量会直接出现在生成节点的输入端。

  • Enum (枚举): 这是一个“可读性”神器。不要用 Int 记录状态(0=跑,1=跳),而要定义一个枚举。它是强类型的,能防止你传错数据,且在 Switch 节点下逻辑极其清晰。

      B. 函数 (Functions) vs. 宏 (Macros) vs. 事件 (Events)

这是最容易混淆的地方:

特性 函数 (Function) 宏 (Macro) 事件 (Event)
底层本质 真正的子程序调用,有自己的局部变量堆栈。 纯粹的“代码展开”,编译时把节点复制到调用处。 程序的入口点,通常用于响应外部信号。
局部变量 支持。 不支持。 不支持。
延迟逻辑 禁止。不能放 DelayTimeline 支持。可以放 Delay 支持。支持所有异步操作。
返回值 可以有多个输出引脚(Return)。 像普通节点,可以有多个输出路径。 无返回值(除非通过参数传递引用)。
适用场景 复杂的数学计算、getter/setter 逻辑。 简单的流转封装、重复的连线组合。 碰撞检测、输入响应、RPC 网络通信。

      C.蓝图接口 (BPI)

  • BPI 沟通协议。

  • 位置: 右键 -> Blueprints -> Blueprint Interface。

  • 使用: 只要物体都带着这个“接口”,不管它是门还是宝箱,玩家发送“交互”信号,它们都能各自执行自己的逻辑,且不需要互相引用对方。

  • 流式加载(Level Streaming)、异步处理、对象池

  • 流式加载 (Level Streaming)

  • 含义: 像看视频缓冲一样加载场景。

  • 实现: 将世界切成 A、B、C 块。当玩家走进 A 触发器,自动加载 B;离开 A 后,卸载 A。UE5 的 World Partition 已经自动化了这个过程。

  • 异步处理 (Asynchronous Processing)
  • 意义: 让耗时任务(加载大贴图、算数学题)不卡死主线程(画面不掉帧)。

  • 实现:

    • 如何实现流式加载(具体操作步骤)

      在 UE5 中,最推荐的是使用 World Partition(世界分区)

    • 开启世界分区: Project Settings -> World Partition -> 勾选 Enable World Partition

    • 设置 Grid(网格):World Partition Editor 窗口中,你可以看到整个场景被切成了无数个小方块。

    • 设置加载范围: 选中网格,设置 Loading Range(例如 50000 厘米)。

    • 运行逻辑: 当玩家角色靠近某个网格,该网格内的模型、贴图会自动从硬盘加载到内存;当玩家远离,它们会自动卸载。

    • 手动流送(Level Streaming): 如果你不用世界分区,可以通过 Load Stream Level 节点,根据触发器(Trigger Box)来手动控制子关卡的加载。

    • Async Load Asset: 蓝图节点,在后台加载东西,加载完后给你个通知。

    • Timer (定时器): 设置逻辑在 5 秒后执行,而不是在 Tick 里每帧判断。

  • 对象池 (Object Pooling)
  • 逻辑: 子弹打出去后,不要销毁 (Destroy),而是隐藏并回收进一个仓库。

  • 目的: 消除频繁创建物体导致的内存碎片和 CPU 高峰。

  • 象池的核心是不进行真正的 Destroy(销毁)和 Spawn(生成),而是进行 显隐状态切换数据重置

  • 调用步骤:

    1. 初始化: 在游戏开始(BeginPlay)时,生成 50 个物体,将它们全部 Set Hidden in Game(true) 并关闭 Collision

    2. 获取(Get): 当你需要子弹时,遍历数组找到第一个“非激活”状态的物体。

    3. 激活: 将该物体的坐标 SetWorldLocation 移动到枪口,开启显示和碰撞。

    4. 回收(Return): 当物体碰到墙壁或存活时间到期,不要销毁,而是再次将其隐藏并移回一个“储藏区”(比如坐标 0,0,-99999)。

  • PSO 卡顿、间歇性延迟(Hitch)的定位与缓解

  • PSO (管线状态对象) 卡顿
  • 痛点: 玩家第一次开火时突然卡一下。

  • 原因: GPU 还没见过这个特效的 Shader,正在现算(编译)。

  • 解决: PSO Caching。在发布前跑一遍游戏,收集所有 Shader 记录,打包进安装包。游戏启动时提前让 GPU 预热这些 Shader。

  • 间歇性延迟 (Hitch)

    指突然跳出的一帧耗时极长。

  • 排查: 通常是 Garbage Collection (GC) 在大规模清理内存,或者是从硬盘读取大资产导致的 I/O 堵塞。

5. 性能分析与优化(TA 核心价值)

  抗锯齿(MSAA vs TAA)与超分技术(FSR、TSR、DLSS),移动端 TBDR 下 MSAA 的收益

合批处理就是合并材质吗?

不完全是,但常常是。“合批”的直接目标是把一堆 Draw Calls 变成一个,共享同一个材质是实现它的核心前提。实际的合批过程是将符合条件的不同物体的顶点数据合并成一个大 Buffer 再提交给 GPU。


GPU 分析工具:RenderDoc、Unreal Insights、移动端 Profiler

stat RHI 给不出具体原因时,你需要这些专业工具:

  • 抗锯齿(Anti-Aliasing)对比

    技术 全称 特点 推荐平台
    FXAA 快速近似 边缘模糊,极快。 低配手机
    TAA 临时抗锯齿 效果好,但画面动起来会糊(鬼影)。 中配手机 / PC
    MSAA 多重采样 画面最清晰,但非常吃显存空间。 移动端首选 (配合 Forward Rendering)
    TSR 临时超分辨率 UE5 特有,类似 DLSS,高清画质。 高端 PC
    SMAA 亚像素形态学 比 FXAA 清晰,比 TAA 快。 中配 PC
  • TBDR 下 MSAA 的收益

    移动端 GPU(如 Adreno/Mali)大多采用 TBDR (分块延迟渲染) 架构。

  • 原理: 手机显卡会将屏幕切成 16x16 的小块(Tiles),在显卡内部极速计算。

  • MSAA 收益: 在这种架构下,MSAA (多重采样抗锯齿) 的计算是在芯片内部完成的,几乎不占用显存带宽。

  • 对比: TAA 需要采样历史帧,会导致手机发热严重且画面模糊;MSAA 则能提供非常锐利且低开销的边缘。

    • 操作: 在移动端开启 Forward Shading (前向渲染),然后开启 MSAA 4x。

  • 超分辨率技术:FSR, TSR, DLSS

    这些技术的目标都是:低分辨率渲染,高分辨率输出。

  • FSR (AMD): 基于数学算法的拉伸。

  • TSR (UE5): 引擎内置的算法,效果比 FSR 更稳定。

  • DLSS (NVIDIA): 必须有 RTX 显卡。它利用 AI(深度学习)来“猜”丢失的像素,效果目前是行业最强。

  • 它们算抗锯齿吗? 算。 它们在放大的同时,利用历史帧信息消除了锯齿,所以它们现在基本替代了传统的 TAA。

  • FSR (AMD FidelityFX Super Resolution): 跨平台的超分辨率技术。

    • 开启: 需下载对应的插件。在 Project Settings 中开启插件后,控制台输入 r.FSR.Enabled 1

  • TSR (Temporal Super-Resolution): UE5 官方自研的抗锯齿+超分辨率技术。

    • 开启: Project Settings -> Rendering -> Anti-Aliasing Method 选为 Temporal Super-Resolution (TSR)

    • 意义: 它们都允许你以 1080P 的分辨率渲染画面,却输出接近 4K 的清晰度

  • 移动端性能策略:内存预分配、带宽优化、发热控制

  • 移动端内存预分配
  • 方法:Project Settings -> Streaming 下,手动设置 Pool Size(纹理池大小)。

  • 目的: 启动游戏时就给贴图划好 512MB 的地盘。这样不会在游戏进行中因为不断申请内存而造成微卡顿。

    纹理池 (Texture Pool) :

    它是一块预留给系统管理的专用显存区域,用于存放游戏运行时会用到的所有纹理。它存在的核心目的,就是为了避免显存被瞬间占满导致游戏卡顿,并在不同纹理间进行高效切换。

  • 移动端性能策略:带宽与发热

    手机端最怕的不是计算量,而是 带宽 (Bandwidth),即数据在内存和显卡之间搬运的速度。

  • 内存预分配: 设置 r.Streaming.PoolSize。给贴图划定地盘,防止系统频繁申请内存。

  • 带宽优化:
    • 减少采样器: 材质中贴图数量越少越好(使用通道打包)。

    • 纹理压缩: 必须使用 ASTC 格式。

  • 发热控制:
    • 限制帧率: 手机端跑 30 帧比不稳定的 60 帧要好得多。

    • 指令减法: 材质指令超过 150 条时,手机外壳就开始烫手了。

  • Draw Call 优化、合批、LOD 与剔除(视锥体、遮挡)

  • Draw Call 是 CPU 告诉 GPU 画东西的次数。 

  • Draw Call优化
  • Draw Call 优化是图形性能优化的核心任务之一。目标很明确:减少 CPU 为提交渲染命令所耗费的时间,让 GPU 尽可能满载。

    下面是经过实践验证的几类主要优化方法,按效果从高到低排列:


    1️⃣ 减少物体数量(最直接)
    方法 原理 示例
    视锥剔除 不提交相机视野外的物体 UE/Unity 自动做,但需合理设置包围盒
    遮挡剔除 不提交被其他物体完全挡住的对象 预计算可见性(如 UE 的 Precomputed Visibility 或 Potentially Visible Sets)
    距离剔除 超出设定距离的物体直接不渲染 远处的小物件、粒子
    LOD 远距离使用低面数模型,虽不减少 DC,但降低顶点/像素负载,间接允许更高 DC 预算 重要
    包围盒 (Bounding Box) :

    是包裹 3D 模型的最小六面体,引擎用它来执行视锥剔除 (Frustum Culling) 和碰撞检测。UE 中默认使用 轴对齐包围盒 (AABB)。你可以在静态网格体编辑器 (Static Mesh Editor) 里为模型添加自定义的简单碰撞盒(如胶囊、盒体等),它也是导航网格生成的基本单位。

    核心:不画看不见的东西。


    2️⃣ 合并 Draw Call

    🔹 静态批处理(Static Batching)

  • 原理:将不移动、不改变材质的多个物体,在构建时合并为一个大网格(须共享同一材质)。

  • 限制:会增加内存(副本网格),每个物体仍独立剔除。

  • 最佳场景:建筑、石头、树木等大量静态场景物体。

  • 🔹 动态批处理(Dynamic Batching)

  • 原理:运行时自动将满足条件(小顶点数、相同材质)的小物体合并到一个 DC。

  • 代价:每帧做合并计算,有 CPU 开销。适用于移动端小物体。

  • 常见:Unity 内置,UE 无等价物(UE 用实例化替代)。

  • 🔹 手动合并网格

  • 原理:在 DCC 软件中将多个物体合并成一个网格,共享一套 UV/材质。

  • 缺点:无法单独控制每个物体的剔除/变换,内存增大。

  • UE 动态批处理中的“实例化”和“静态批处理”有什么区别?

    它们的目标都是减少 Draw Call,但路子完全不同。

  • 静态批处理 (Static Batching):在编辑时就合并不同物体的网格。优点是合批效率最高,但不支持运行时移动。

  • 实例化 (Instancing):在运行时使用一个网格和材质,通过传递不同参数(如位置、颜色)一次性绘制多个物体。支持动态,但不适用于骨骼网格体模型。

  • 3️⃣ GPU 实例化(Instancing)

    方法 说明 支持情况
    传统实例化 一次 DC 绘制多个相同网格、相同材质的物体,仅传递不同变换矩阵 DirectX 11+ / Vulkan / Metal
    GPU Instancing 自动合并大量相同物体的渲染 Unity 的 Graphics.DrawMeshInstanced、UE 的 Instanced Static Meshes
    间接实例化 由 GPU 自己决定绘制多少实例(例如视锥剔除写在 Compute Shader 中) 高级用法,HPC 渲染

    :材质必须一致(允许贴图数组或 Per-instance 数据)。


  • 4️⃣ 减少材质 / 着色器切换

  • 排序渲染队列:将所有物体按材质 ID 排序 → 相同材质的连续画完。

  • 使用材质实例:但注意实例不切换 Shader,切换材质参数开销极低;切换 Shader 或材质资源本身才是重量级操作。

  • 合并纹理图集:将多个小贴图合成一张大图,使不同物体可共用同一材质(相同材质参数)。

  • 排序渲染队列怎么能体现出优化?
  • 对不透明物体,它减少了 GPU“画了又被盖住”的透支开销

  • 对于半透明物体,不排序会导致严重的视觉错误,比如透过窗户能直接看到墙壁背面的场景。

  • 排序也能减少 GPU 状态切换,比如把使用相同材质 Shader 的物体排在一起渲染。

  • 5️⃣ 利用 Advance 渲染技术

    技术 降低 DC 的方式
    GPU Driven Rendering CPU 只提交一个或几个 DC,GPU 自己做剔除、间接绘制(如 Mesh Shader 或 ExecuteIndirect)
    Nanite(UE5) 虚拟几何体系统,几何体粒度极细,但内部自动合并渲染,对用户透明
    Batch 批 DX12 / Vulkan 下多 DC 可以打包进一个 Command List,减少 CPU 调用次数(但不是合并几何体)
  • ⚙️ 合批、LOD 与剔除三者的协作顺序(典型帧内)

  • 视锥剔除(CPU)→ 剔除完全看不见的物体。

  • 遮挡剔除(CPU + 可选 GPU 查询)→ 剔除被挡住的部分物体。

  • LOD 选择(CPU)→ 对剩下的物体,根据距离选择对应的网格。

  • 合批(CPU)→ 将使用相同材质、符合合批条件的物体整理成更大的批次。

  • 渲染(GPU)→ 提交批次,执行顶点/像素着色器。

  • 注意:如果采用了 GPU Driven 渲染(如 Nanite),剔除和 LOD 全部移到 GPU 端,CPU 只负责很少的 Draw Call。

  • 技术 目标 执行位置 减少什么 典型代价
    视锥剔除 去掉镜头外的物体 CPU 不需要的 Draw Call
    遮挡剔除 去掉被挡住的物体 CPU/GPU 不必要的渲染 (overdraw) 中(预计算)或高(实时)
    LOD 远处物体简化 CPU 顶点/像素处理量 低(内存换性能)
    合批 减少 Draw Call CPU CPU 渲染线程耗时 内存、合并开销

    最佳实践:优先保证剔除正确,其次使用 LOD 控制负载,最后用合批压榨 CPU 提交效率。

  • 🧠 记忆口诀

    看不到的不画(剔除),相同的合并(批处理),同类的一次画(实例化),材质别老换(排序),能用 GPU 让 GPU 干。

  • Unreal Insights:  它能录制 CPU 每一微秒在干什么。如果是因为某个蓝图 Tick 太重,或者某个渲染指令堵塞,它会显示一条长长的红色色块。

  • RenderDoc: 它可以“冻结”一帧,让你看 GPU 画这一帧的每一个步骤(Step-by-step)。你可以看到是哪一个 Draw Call 耗时最长。

  • 移动端 Profiler: 苹果用 Xcode Instruments,高通安卓用 Snapdragon Profiler。它们能直接读到手机芯片的实时负载。

6. 工程与规范

  • SVN / Git 版本控制,资产锁定与提交规范

  • SVN (Subversion):

    一种版本控制系统(类似 Git)。由于游戏项目的文件(模型、贴图)非常大,Git 处理起来很吃力,所以游戏行业大量使用 SVN 来管理美术资产。它能记录谁改了哪个贴图,并允许你回退版本。

  • 游戏内的“黑盒”:

    通常指功能封装。在 UE 中,通过将复杂的逻辑封装在 Material FunctionBlueprint Class 中,只暴露几个接口(Input/Output)。外部不需要知道内部怎么算的,只需要给输入值,这就是“黑盒”思维。

  • SVN 详细操作指南(资产版本管理)

    SVN 对美术资产(.uasset)的支持远好于 Git。

  • Checkout (检出): 把服务器仓库的东西拉到本地电脑。

  • Lock (加锁): 最关键步骤! 改模型/贴图前必须点 Lock,防止别人也改它,因为 .uasset 文件无法合并冲突。

  • Update (更新): 每天开工第一件事。

  • Commit (提交): 改完了解锁并上传。

  • Revert (回退): 改乱了?直接一键回到服务器上的版本。

  • 如何实现 SVN(详细设置流程)

    SVN 的核心是 “服务器 + 客户端” 架构。

  • 安装服务端(如 VisualSVN Server): 找一台不关机的电脑(或云服务器),安装并新建一个 Repository(仓库)。你会得到一个 URL 链接。

  • 安装客户端(TortoiseSVN): 在你的工作电脑安装它(俗称“小乌龟”)。

  • 检出项目(Checkout): 在你的硬盘空白处右键 -> SVN Checkout -> 输入服务器的 URL。

  • UE 集成: 在 UE 编辑器下方的 Source Control -> Connect to Source Control -> 选择 Subversion -> 填写 URL、账号、密码。

  • 操作: 以后在内容浏览器里改了东西,右键就有 Check Out(加锁)和 Submit(上传)选项了。

  • Git 是什么?

    Git 是目前全球最流行的分布式版本管理系统

  • 对比 SVN: SVN 只有一个中央仓库;Git 每个人本地都有一个完整的仓库副本。

  • 优势: 适合代码管理,分支合并非常强大。

  • 劣势: 处理巨大的美术资产(如 1GB 的贴图)时非常笨重,容易导致仓库体积爆炸。

  • 资产锁定与提交规范

    在团队开发(SVN/Perforce)中,为了防止文件冲突:

  • Check Out (锁定): 修改 .uasset 前必须先锁定。UE 中图标会变成一个红色的勾,别人就没法改了。

  • 原子提交: 相关的修改(比如你改了模型和对应的材质)要放在同一个提交记录(Changelist)里。

  • Submit (提交): 提交后系统会自动解锁,别人才能同步你的修改。

  • 资产存储位置对照表,命名规范与配置层级

  • 资产存储位置对照表

    资产类型 存储位置 硬件处理核心
    UV 坐标 存在模型(Mesh)的顶点数据中 GPU (Vertex Shader) 负责读取
    贴图 (Texture) 存在显存 (VRAM) 中 GPU (Pixel Shader) 负责采样
    游戏逻辑 存在内存 (RAM) 中 CPU 负责计算
    RHI 指令 内存缓存区 CPU 生成,发往 GPU 执行

命名规范与配置层级

  • 命名规范:

    • 贴图:T_BaseColor_D(D 代表 Diffuse/Data)。

    • 材质:M_Master(母材质),MI_Snow(材质实例)。

    • 蓝图:BP_WeatherSystem

  • 配置层级 (Config Hierarchy): UE 的设置读取顺序是:Engine -> Project -> Platform (如 Android) -> User

    • 实战: 如果你想针对手机降画质,不要改 DefaultEngine.ini,而要改 Android/AndroidEngine.ini

实践层

  1. Shader 与材质的硬指标

    • 材质复杂度视图:必须能用引擎自带的“Shader Complexity”视图,一眼看出哪个材质是“性能杀手”(例如:绿色好,红色坏,白色直接爆了)。

    • 具体指令数达标线:你需要知道,对于移动端,一个像素着色器的指令数最好控制在多少条以内(例如:基础物体 < 100 条,角色 < 200 条)。

    • 这就是要把我之前汇总的节点知识,结合到这个框架的“3.2 材质逻辑与性能”里去学。

  2. 具体的工具操作流

    • RenderDoc 截帧五步法:虽然框架里提了工具,但你需要知道具体的查看顺序(先看 Pass 数量,再看 Draw Call 密度,最后选一条 Draw Call 看输入输出)。

    • Unreal Insights 的 Trace:知道怎么开启、停止、导出,然后看哪几个关键线程(GameThread, RenderThread, RHIThread)的耗时。

  3. 针对流派的具体优化手册

    • 移动端特有坑:除了 TBDR,你还得知道 Alpha Test 对移动端杀伤力为何特别大(会禁用 Early-Z 或 HS R 优化),以及为什么非等宽纹理(NPOT)在部分老设备是地雷。

    • Lumen/Nanite 的“禁区”:知道什么情况下 Lumen 开销暴增(比如大面积植被),以及 Nanite 不支持的东西(动态模型、Masked 材质在移动端不做 Nanite 等)。

1. 节点与指令的对应关系:从图形到文本

在 UE 中,材质编辑器通过连线生成一份巨大的 Material.usf 文件。要理解代码,首先要建立“翻译”直觉。

如何查看 HLSL 代码

在材质编辑器菜单栏,点击 窗口 (Window) -> HLSL 代码 (HLSL Code)。你会看到一个极其冗长的文档,核心逻辑通常隐藏在以 CalcPixelMaterialParametersGetMaterialPixelParameters 开头的函数中。

常用节点与代码映射表

材质节点 HLSL 代码/表达 逻辑说明
Add a + b 两个向量或数值相加
Multiply a * b 逐元素相乘
Lerp lerp(a, b, s) 线性插值:$a(1-s) + b(s)$
Dot Product dot(a, b) 点积,常用于计算光照角度($\cos\theta$)
Texture Sample Texture2DSample(Tex, TexSampler, UV) 纹理采样函数
Component Mask value.rgvalue.r 获取向量的特定通道(Swizzling)

建议: 试着连接一个最简单的 Add 节点,然后在 HLSL 窗口里搜索 + 号,观察它是如何嵌套在函数体内的。


2. PBR 公式的 Shader 落地

PBR(基于物理的渲染)的核心目标是让材质在不同光照环境下表现一致。

BRDF 与 GGX

UE 主要使用 Cook-Torrance BRDF 模型。它将反射分为两个部分:漫反射(Diffuse)镜面反射(Specular)

  • GGX (Microfacet Distribution): 这是目前主流的法线分布函数。代码实现的核心是计算“微平面”有多大比例朝向相机。其公式在代码中体现为:

    $$D(h) = \frac{\alpha^2}{\pi( (n \cdot h)^2 (\alpha^2 - 1) + 1 )^2}$$

    其中 $\alpha$ 就是 Roughness 的平方。这就是为什么 Roughness 变化对高光形状影响如此之大的原因。

能量守恒(Energy Conservation)

在代码中,能量守恒遵循一个铁律:反射出去的光不能超过接收到的光

  • 实现方式: Specular + Diffuse <= 1

  • 在 UE 代码中,当你增加 Metallic(金属度)时,代码会通过 lerp 自动降低 BaseColor 对漫反射的贡献,将其转化为镜面反射的颜色。

Roughness/Metallic 如何驱动采样

  • Metallic: 决定了 BaseColor 是作为漫反射(0)还是作为镜面反射颜色(1)。

  • Roughness: 决定了在采样环境贴图(CubeMap)时,使用哪一个层级的 Mipmap。越粗糙,采样越模糊(Mip 级别越高)。


3. 顶点着色器 (VS) 与 像素着色器 (PS) 的分工

理解这两者的分工是优化的基础。

顶点着色器 (Vertex Shader)

  • 职责: 处理几何体信息(顶点位置、法线、切线)。

  • 代码体现: World Position Offset (WPO)

  • 优势: 计算频率低。一个 1 万面的模型只有约 5000 到 1 万个顶点。在此执行动画计算(如树叶摆动、时钟旋转)非常省资源。

像素着色器 (Pixel Shader)

  • 职责: 处理每个像素的最终颜色。

  • 代码体现: 几乎所有的纹理采样、光照计算。

  • 劣势: 计算频率极高。在 1080p 屏幕下,每帧要运行约 200 万次计算。

性能准则: 如果一个计算逻辑(比如平移 UV 的 Time 计算)可以在 VS 中完成,就不要放在 PS 里。UE 材质节点中的 Vertex Interpolator(顶点插值器)节点就是专门干这个的:在 VS 计算结果,然后传给 PS 直接使用。


4. 常用性能陷阱:避坑指南

Alpha Test (Masked) 与 Early-Z

  • 陷阱: 在移动端或低性能平台,使用 Masked(遮罩)模式会破坏硬件的 Early-Z 优化。

  • 原理: 显卡本可以在计算像素前就知道哪些物体被遮挡了,从而跳过计算。但如果使用了遮罩,显卡必须运行完 Shader 才知道这个像素是不是透明的,导致严重的性能浪费。

  • 对策: 尽可能使用几何体剪裁,或者接受半透明(Translucent)的开销。

半透明排序与 Overdraw

  • Overdraw(过度绘制): 当多个透明层重叠时,同一个像素会被重复计算多次。

  • 可视化检查: 在编辑器运行模式下,选择 优化视图模式 (Optimization Viewmodes) -> Overdraw。深红色或白色代表该处性能压力极大。

动态材质实例 (MID) 的参数更新

  • 性能消耗:Tick 中使用 SetScalarParameterValue 是有开销的,因为它涉及到从 CPU 向 GPU 发送指令。

  • 对策: 如果参数变化非常频繁(如每一帧都在变),考虑使用 Material Parameter Collection (MPC) 或者 Vertex Color 来传递数据,减少 API 调用次数。

  • 网格体距离场 是一个能快速判断“点到物体表面距离”的技术,主要用于高效的动态阴影和软环境光遮蔽(AO)。

  • Render Target 是一个渲染的“幕后画板”,先在它上面绘制,再把结果用作纹理,是实现反射、动态特殊效果的基础。

  • Lightmap 则是预先生成的静态“光照照片”,通过预计算将静态光照细节存入纹理,是兼顾高性能与高画质的基石。

  • Virtual Shadow Maps (VSM) 是UE5主推的高性能虚拟化阴影技术,是为Nanite等精细化资产配套的高级动态阴影方案。

下面我们来看看它们的具体作用。

📏 网格体距离场 (Mesh Distance Field)

它的核心是一个有向距离场(Signed Distance Field,SDF)。简单来说,它会用一个体积纹理记录空间中的每一个点,到它最近的物体表面有多远:点在物体外部为正值,内部为负值。

这个技术的主要作用包括:

  • 产生软阴影(Distance Field Shadows):比传统级联阴影贴图(CSM)更省性能,擅长为远处的物体投射柔和、自然的半影区域。

  • 制作动态环境光遮蔽(Distance Field Ambient Occlusion):实现动态、柔和的全局遮蔽效果,让场景的立体感大幅提升。

  • GPU粒子碰撞:让粒子能高效地识别并与场景中的静态物体产生互动。

  • 材质特效:你甚至可以在材质编辑器里引用它,制作出动态的流动贴图等有趣效果。

使用方法上,你可以在项目的渲染(Rendering) > 软件光线追踪(Software Ray Tracing)菜单下,通过勾选 生成网格体距离场 来为整个项目全局开启,这会增加一些构建时间和内存开销。开启后,在定向光源距离场阴影分类下勾选启用,并通过距离场阴影距离等参数调节作用范围和质量。


🖼️ 渲染目标(Render Target)

Render Target可以理解为GPU内部的一块“离屏”画板。常规渲染流程会直接绘制到屏幕,但有了渲染目标,我们可以先在幕后画板上创作,绘制好的画面能被当作纹理在后续流程中使用,为各种高级特效提供了基础。这种先离屏绘制再作为纹理使用的思路,是实现许多画面效果的关键。

你可以这样使用它:

  1. 创建:就像买一块新画板,需要在代码中创建一个指定宽高的RenderTarget对象。

  2. 绘制:通知GPU“接下来请画在这块新画板上”,引擎会开始将几何体渲染到这个目标的内部中。

  3. 应用:绘制完成后,就到了一展身手的时候。生成的图像可以被当作普通纹理用在材质里,或者再次采样进行后处理。

  4. 复原:记得最后要把绘制目标重置回原始的“屏幕”(即Back Buffer),否则后面的画面就不知道画到哪儿去了。

利用这个工作流,你可以实现很多酷炫的效果:

  • 实时镜子/监视器:创建一个渲染目标,内容来自镜子位置的相机,然后像贴图一样贴在模型上。

  • 后处理特效:将整个场景先画到一个渲染目标上,再用一个全屏着色器对它进行处理,便能得到模糊、泛光等滤镜效果。

  • 动态贴花:为了绘制一个弹孔,可以先把它渲染到一个独立的纹理,再投射到场景中。

  • 小地图:用一个俯视相机将地图渲染到渲染目标上,就能生成实时更新的2D小地图。


💡 光照贴图(Lightmap)

Lightmap的核心思想叫光照烘焙(Light Baking),也就是预先计算场景中静态物体的光照信息,并将结果保存到一张或多张纹理中。运行时,材质直接采样这张图来获取明暗信息,就像一个物体自带了光照贴纸。它能以很低的开销输出高质量的静态光照效果。

它的渲染过程如下:

  1. 准备标记:在编辑器中将所有不动的物体和光源标记为“静态 (Static)”,表示它们参与光照烘焙。

  2. 分配坐标:引擎准备好模型专用的第二套UV通道(Lightmap UVs),用于在光照贴图上正确展开渲染结果。

  3. 执行烘焙:按下“烘焙 (Bake)”按钮,引擎(如Unity的Progressive Lightmapper)开始全局光照计算。

  4. 最终应用:烘焙完成,引擎自动将光照贴图与模型关联。运行时,Shader会把这张纹理和主纹理混合,展现出最终光影效果。

简单来说就是:准备标记 -> 分配坐标 -> 执行烘焙 -> 最终应用

预计算可见性 (Precomputed Visibility):

本质是解决“哪些地方能看到哪些东西”的问题提前算好,运行时直接查表。主要适用于移动平台或有大面积遮挡物的场景。

操作步骤:在 World Settings > Precomputed Visibility 勾选启用,然后在关卡中放置 Precomputed Visibility Volume 调整其覆盖范围。最后重新构建光照 (Build Lighting),数据便生成完毕并进行剔除。


🎭 虚拟阴影贴图(Virtual Shadow Maps,VSM)

VSM是UE5推出的一项革命性的高精度阴影贴图技术。它的核心是虚拟化:维护一张16k x 16k像素的超大虚拟阴影贴图,再将它划分为许多128x128的小块(页),按需动态加载,实时渲染画面中的高精度阴影。

它的主要作用包括:

  • 惊人的视觉精度:能完美配合Nanite的超高精度几何体,不再需要在阴影质量和性能间做痛苦的权衡。

  • 全局统一的柔和阴影:为整个场景提供统一、物理正确的柔和阴影边缘(半影区),大大提升了真实感。

  • 简化的工作流程:旨在提供一种“开箱即用”的设置,自动适应项目需求,几乎不需要手动调整复杂的参数。

使用方法上,你可以在项目设置的引擎(Engine) > 渲染(Rendering)中,将阴影贴图方法设置为 虚拟阴影贴图 (新项目默认开启),启用后它将替换掉CSM等传统阴影方案。

额外

  • 后处理效果:掌握 SceneTexture 节点的用途,写一个基于深度的雾效。

  • 自定义节点:在材质中使用 Custom 节点插入 HLSL 代码,实现节点做不到的循环或数学操作。

  • 移动端专用 Shader:理解 TBDR 下尽量减少 Render Target 切换,利用 min16float 等低精度。

  • Compute Shader(高级):用 Niagara 或 RenderGraph 驱动 GPU 粒子或流体,这是加分项。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐