> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wanyouxi.online/llms.txt
> Use this file to discover all available pages before exploring further.

# 性能预算与优化标准

> **摘要**：本文聚焦「性能预算与优化标准」，梳理核心概念、关键方法与落地实践。

为了确保游戏在目标平台（PC 中低配 / Steam Deck / 潜在的主机）上稳定运行 60FPS，必须严格执行此预算。

## 1. 概述与目标 (Overview & Targets)

### 目标平台规格 (Target Specs)

* **基准平台:** GTX 1060 / Steam Deck.
* **目标帧率:** 60 FPS (16.6ms per frame).
* **分辨率:** 1080p.

### 性能分级策略 (LOD Policy)

| 设置       | 阴影            | 抗锯齿  | 怪物数量         | 粒子密度 |
| :------- | :------------ | :--- | :----------- | :--- |
| **Low**  | 仅主角           | FXAA | 200 (超过不再生成) | 50%  |
| **Med**  | 实时硬阴影         | SMAA | 350          | 75%  |
| **High** | 软阴影 (Cascade) | TAA  | 500          | 100% |

### 时间感知速查表

将各种操作放入同一个时间尺度中理解：

| 操作          | 耗时量级   | 16.6ms 帧预算占比 | 直觉类比            |
| :---------- | :----- | :----------- | :-------------- |
| L1 Cache 访问 | 1 ns   | 0.00006%     | 眨眼的 1/1,000,000 |
| L2 Cache 访问 | 4 ns   | 0.00024%     |                 |
| 主内存访问       | 100 ns | 0.0006%      |                 |
| SSD 读取      | 100 us | 0.6%         |                 |
| HDD 读取      | 10 ms  | **60%** ⚠️   | 半帧没了            |
| 网络延迟 (同城)   | 5 ms   | 30%          |                 |
| 网络延迟 (跨国)   | 200 ms | **1200%**    | 12 帧！           |
| 完整 GC       | 50 ms  | **300%**     | 3 帧全卡           |

***

## 2. 内存预算 (Memory Budget)

### 内存预算 (Memory Budget)

* **总内存:** \< 4GB (System RAM).
* **显存 (VRAM):** \< 2GB.
* **纹理:**
  * 角色: 2048x2048 (Atlas).
  * 环境: 1024x1024 (Tiling).
  * 杂兵: 512x512 或 1024 合集。
  * *压缩:* PC 使用 DXT5/BC7, 移动端使用 ASTC。

### 内存微观基准 (Memory Micro-Benchmarks)

以下数据为 **近似值**，用于估算内存占用。

#### 1. 基础数据类型 (C#)

| 类型 (C#)            | 大小 (Bytes) | 备注                                             |
| :----------------- | :--------- | :--------------------------------------------- |
| `bool`             | 1 (or 4)   | 单个字段通常对齐到 4 字节，数组中为 1 字节。                      |
| `byte` / `sbyte`   | 1          | 最小单位。                                          |
| `char`             | 2          | UTF-16 字符。                                     |
| `short` / `ushort` | 2          |                                                |
| `int` / `uint`     | 4          | 最常用的整数。                                        |
| `float`            | 4          | 物理、坐标常用。                                       |
| `long` / `ulong`   | 8          | 大数。                                            |
| `double`           | 8          | 高精度计算。                                         |
| `Reference` (引用)   | 8          | 64 位系统指针大小。Class 的引用。                          |
| **Object Header**  | \~16-24    | 每个 `class` 对象实例的额外开销 (SyncBlock + TypeHandle)。 |

> **⚠️ 小对象陷阱:** 创建一个只包含 1 个 `int` 的 `class` 实例，其实际占用可能高达 **24-32 bytes** (Header + int + Padding)。**大量小对象必须用 `struct`。**

#### 1.1 Struct vs Class 内存深度对比

| 特性                  | Class (引用类型)                  | Struct (值类型)                    | 备注                            |
| :------------------ | :---------------------------- | :------------------------------ | :---------------------------- |
| **分配位置**            | 堆 (Heap)                      | 栈 (Stack) 或 嵌入在父对象中             | Class 导致内存碎片和 GC。             |
| **额外开销 (Overhead)** | **\~16-24 Bytes** (Header)    | **0 Bytes**                     | Struct 没有对象头。                 |
| **引用开销**            | **8 Bytes** (64 位指针)          | 0 Bytes                         | Class 变量存的是指针，Struct 存的是数据本身。 |
| **数组内存布局**          | **指针数组**: `[Ptr1, Ptr2, ...]` | **连续数据**: `[Data1, Data2, ...]` | Struct 数组对 CPU Cache 极其友好。    |
| **GC 压力**           | **高**: 需回收对象头                 | **无**: 随栈/父对象销毁                 | 只要不装箱 (Boxing)，Struct 零 GC。   |

**内存布局示例 (含 2 个 int 的对象):**

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
Class Point { int x; int y; }  // 堆上: [Header 16B] + [x 4B] + [y 4B] = 24 Bytes + [栈上指针 8B] = 32 Bytes
Struct Point { int x; int y; } // 栈上/数组内: [x 4B] + [y 4B] = 8 Bytes (纯数据, 无额外开销)
```

#### 2. Unity 对象开销 (空对象)

| 对象类型                 | 内存占用 (估算)         | 备注                                          |
| :------------------- | :---------------- | :------------------------------------------ |
| `GameObject` (Empty) | \~100 - 200 Bytes | C++ 原生非托管内存 + C# 包装器。                       |
| `Transform`          | \~400 - 500 Bytes | 含 Position, Rotation, Scale, 矩阵缓存, 父子指针。很重！ |
| **Empty GameObject** | **\~0.5 - 1 KB**  | 一个空的 GameObject + Transform 的总开销。           |
| `MeshFilter`         | \~100 Bytes       | 仅引用 Mesh。                                   |
| `MeshRenderer`       | \~300 Bytes       | 引用材质和 AABB。                                 |

#### 3. 纹理内存 (Texture Memory)

**公式:** `宽 x 高 x BytesPerPixel`

| 格式              | Bits/Pixel | Bytes/Pixel | 1024x1024 大小       | 说明                    |
| :-------------- | :--------- | :---------- | :----------------- | :-------------------- |
| **RGBA 32 bit** | 32         | 4           | **4 MB**           | 无压缩，最高画质。UI/图标常用。     |
| **RGB 24 bit**  | 24         | 3           | **3 MB**           | 无透明通道。不推荐 (对齐问题)。     |
| **RGBA 16 bit** | 16         | 2           | **2 MB**           | 抖动明显 (Dither)。复古风可用。  |
| **Alpha 8**     | 8          | 1           | **1 MB**           | 单通道掩码/SDF。            |
| **DXT1 / BC1**  | 4          | 0.5         | **0.5 MB (1/8)**   | PC 标准压缩 (无透明/Cutout)。 |
| **DXT5 / BC3**  | 8          | 1           | **1 MB (1/4)**     | PC 标准压缩 (全透明)。        |
| **BC7**         | 8          | 1           | **1 MB (1/4)**     | PC 高质量压缩 (推荐)。        |
| **ASTC 4x4**    | 8          | 1           | **1 MB (1/4)**     | 移动端高质量。               |
| **ASTC 6x6**    | 3.56       | \~0.45      | **0.45 MB**        | 移动端均衡 (推荐)。           |
| **ASTC 8x8**    | 2          | 0.25        | **0.25 MB (1/16)** | 移动端低配/特效/背景。          |

#### 4. 网格数据 (Mesh Data)

> *详细数据请参阅 [图形预算 > 模型与骨骼动画性能](#模型与骨骼动画性能)*

#### 5. 音频内存 (Audio Memory)

| 格式               | 压缩比 (近似)    | 1 分钟立体声大小 (44.1kHz) | 建议                         |
| :--------------- | :---------- | :------------------ | :------------------------- |
| **PCM (WAV)**    | 1:1 (无压缩)   | **\~10 MB**         | 仅用于极短、极低延迟的音效 (UI 点击)。     |
| **ADPCM**        | \~3.5:1     | **\~3 MB**          | 频繁播放的短音效 (脚步、枪声)。CPU 开销极低。 |
| **Vorbis / MP3** | \~10:1 (可变) | **\~1 MB**          | 背景音乐 (BGM)、长语音。CPU 开销较高。   |

***

## 3. 程序预算 (Program/CPU Budget)

### CPU 预算 (CPU Budget)

Roguelike + 塔防意味着海量实体，CPU 是最大瓶颈。

* **同屏单位数:** 最大 500 (怪物 + 塔 + 投射物)。
* **AI 更新频率:**
  * 近处怪物 (\<20m): 每帧更新。
  * 远处怪物 (>20m): 每 3-5 帧更新一次逻辑 (Time Slicing)。
  * 不可见怪物: 仅更新位置，暂停动画和物理。
* **物理 (Physics):**
  * 使用 `Physics.Simulate` 或 DOTS Physics。
  * **禁止**使用 MeshCollider 对动态物体。全部使用 Sphere/Capsule/Box。
* **垃圾回收 (GC):**
  * 战斗中 **禁止** `new` 操作。
  * 所有投射物、特效、伤害飘字必须使用 **Object Pool**。

### 优化技术栈 (Tech Stack)

#### 1. DOTS (Data-Oriented Technology Stack)

对于海量怪物的移动和简单逻辑，考虑使用 ECS (Entities) + Burst Compiler。这是解决千人同屏的终极方案。

***

#### 🧠 DOTS 性能提升原理详解

DOTS 的核心不是"新技术"，而是**让代码适配现代 CPU 的物理特性**。

##### 1. 内存布局：AoS vs SoA

传统 OOP (Array of Structs):

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
[Entity1: Position, Rotation, Health, AI...]
[Entity2: Position, Rotation, Health, AI...]  ← 内存中交错排列
[Entity3: Position, Rotation, Health, AI...]
```

ECS (Struct of Arrays):

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
Positions: [Pos1, Pos2, Pos3, ...]   ← 同类型数据连续存储
Rotations: [Rot1, Rot2, Rot3, ...]
Healths:   [HP1,  HP2,  HP3,  ...]
```

**为什么 SoA 更快？** 参考 [CPU 下的 Cache Miss](#cpu-下的-cache-miss：隐形杀手)：

| 场景                      | OOP (AoS)                       | ECS (SoA)                  | 原因             |
| :---------------------- | :------------------------------ | :------------------------- | :------------- |
| **遍历 10000 个 Position** | 加载整个 Entity (\~100 bytes)       | 只加载 Position (12 bytes)    | 减少 **8x** 内存读取 |
| **Cache Line 利用率**      | 每条 Cache Line (64B) 只有 \~12B 有用 | 整条 Cache Line 全部是 Position | **5x** 利用率提升   |
| **Prefetch 效率**         | 随机跳转，Prefetcher 失效              | 顺序访问，Prefetcher 全中         | **100x** 速度差距  |

##### 2. Burst Compiler：SIMD 向量化

Burst 将 C# 代码编译为**原生机器码**，并自动应用 SIMD (Single Instruction, Multiple Data)：

| 操作               | 普通 C# | Burst + SIMD   | 加速比        |
| :--------------- | :---- | :------------- | :--------- |
| **4 个 float 加法** | 4 条指令 | 1 条 SSE/AVX 指令 | **4x**     |
| **8 个 float 乘法** | 8 条指令 | 1 条 AVX 指令     | **8x**     |
| **循环 + 条件判断**    | 逐个处理  | 自动展开 + 无分支     | **10-50x** |

##### 3. Job System：多核并行

Unity 传统 MonoBehaviour 只能跑在**主线程**。Job System 让逻辑分发到所有 CPU 核心：

| CPU 核心数 | MonoBehaviour | Jobs (理论) | 实际加速        |
| :------ | :------------ | :-------- | :---------- |
| 4 核     | 1x            | 4x        | \~3x (调度开销) |
| 8 核     | 1x            | 8x        | \~5-6x      |
| 16 核    | 1x            | 16x       | \~8-10x     |

##### 4. 综合性能对比 (实测参考)

场景：**移动 10000 个 Entity** (每帧更新 Position)

| 方案                            | 耗时 (每帧)        | 对比基准          |
| :---------------------------- | :------------- | :------------ |
| **MonoBehaviour + Transform** | \~15-25 ms     | 100% (基准)     |
| **纯 C# 脚本 (无 Burst)**         | \~5-10 ms      | \~50%         |
| **ECS (无 Burst)**             | \~2-4 ms       | \~20%         |
| **ECS + Burst**               | \~0.3-0.8 ms   | **\~3%**      |
| **ECS + Burst + Jobs (8 核)**  | \~0.05-0.15 ms | **\~0.5%** 🚀 |

> **🚀 结论:** DOTS 全栈可以带来 **50-200x** 的性能提升，核心原因：
>
> * **Cache 友好**: 连续内存，Prefetch 全中
> * **SIMD**: 一条指令处理多个数据
> * **多核**: 充分利用现代 CPU 所有核心
> * **无 GC**: 使用 NativeArray，战斗中零分配

***

#### 2. GPU Skinning

将骨骼动画计算从 CPU 转移到 GPU Shader，解放 CPU 算力。

#### 3. Addressables

资源按需加载，避免启动时加载所有资源导致内存溢出。

### CPU 微观基准 (CPU Micro-Benchmarks)

以下数据为**近似值**（基于现代 PC/Console 架构），用于指导代码编写。

#### CPU 下的 Cache Miss：隐形杀手

现代 CPU 极快，瓶颈通常在**内存墙 (Memory Wall)**。
假设 CPU 主频 3GHz (1 cycle ≈ 0.33ns)。执行 **100 万次** 操作的理论时间差异：

| 存储层级         | 访问延迟 (Cycles)  | 访问时间 (ns)       | 100 万次访问总耗时 (理想估算)    | 类比             |
| :----------- | :------------- | :-------------- | :-------------------- | :------------- |
| **L1 Cache** | 3 - 4          | 1 ns            | **0.5 - 1 ms**        | 从桌子上拿一张纸       |
| **L2 Cache** | 10 - 12        | 3 - 4 ns        | **3 - 4 ms**          | 从书架上拿一本书       |
| **L3 Cache** | 30 - 70        | 10 - 20 ns      | **10 - 20 ms**        | 从隔壁房间拿一本书      |
| **Main RAM** | **200 - 300+** | **60 - 100 ns** | **60 - 100 ms** (掉帧!) | **下楼去图书馆拿一本书** |

> **⚠️ 结论:**
>
> * **顺序数组遍历 (Data Oriented):** CPU 预取器 (Prefetcher) 极其高效，几乎全中 L1/L2。100 万次遍历 = 1-2ms。
> * **随机指针跳转 (OOP/Linked List):** 也就是传统 `class` 引用满天飞。每次跳转都可能是 Cache Miss。100 万次跳转 = **100ms** (直接卡死由 60FPS 跌至 10FPS)。
> * **这就是为什么我们要用 Struct 数组和 Object Pool (保持内存连续)。**

#### Unity 常见 API 热点估算

基于 PC 平台 (i7 级别单核) 的粗略估算。移动端请将时间 **x5 - x10**。

| 操作                             | 近似耗时 (每次)            | 1000 次耗时        | 危险等级      | 建议                                               |
| :----------------------------- | :------------------- | :-------------- | :-------- | :----------------------------------------------- |
| `transform.position` (get/set) | \~20 ns              | 0.02 ms         | 🟢 安全     | 稍微有点开销 (C++到 C# marshalling)，但在热循环中还是尽量缓存。       |
| `GetComponent<T>()`            | \~100 - 300 ns       | 0.1 - 0.3 ms    | 🟡 留意     | 不要在 `Update` 里调。在 `Awake` 缓存。                    |
| `GameObject.Instantiate`       | **0.1 ms - 5.0 ms+** | **100ms+ (卡顿)** | 🔴 **致命** | 必须用对象池。包含复杂组件/子物体时极慢。                            |
| `Destroy()`                    | \~0.05 ms+           | 50ms+           | 🟠 严重     | 触发 GC，导致后续卡顿。                                    |
| `FindObjectOfType`             | **线性遍历全场景**          | **N/A**         | 🔴 **禁止** | 随着场景物体增多呈线性增长。运行时绝不要用。                           |
| `Camera.main`                  | \~2 ms (老版本)         | N/A             | 🟠 慢      | 内部是 FindByTag。新版 Unity 有优化，但仍建议手动缓存 `Singleton`。 |
| `Debug.Log`                    | **0.1 ms+**          | **100ms+**      | 🔴 **卡顿** | 涉及字符串拼接、堆栈抓取、IO。正式包必须剔除。                         |
| `Physics.Raycast`              | \~1 - 5 us           | 1 - 5 ms        | 🟡 适中     | 取决于场景碰撞体数量。尽量用 LayerMask 过滤。                     |

#### GC (垃圾回收) 开销

.NET/Mono 的 GC 是\*\*"Stop The World"\*\*模式，一旦触发，主线程暂停。

| GC 类型           | 近似耗时             | 触发条件                      | 危险等级          |
| :-------------- | :--------------- | :------------------------ | :------------ |
| **Gen0 (快速回收)** | **0.5 - 2 ms**   | 临时小对象 (如 lambda 捕获、临时字符串) | 🟡 频繁则累积      |
| **Gen1 (中等回收)** | **2 - 10 ms**    | 存活过一次 Gen0 的对象            | 🟠 明显卡顿       |
| **Gen2 (完整回收)** | **10 - 100+ ms** | 长期生存的大对象、大数组              | 🔴 **灾难性帧卡顿** |

> **⚠️ 重要结论:**
>
> * **每帧分配 1KB 内存**：约每秒触发 1 次 Gen0 GC (\~1-2ms 卡顿)。
> * **战斗中禁止 `new`**：所有对象必须预分配或使用对象池。
> * **String 拼接是 GC 大户**：每次 `"a" + "b"` 都产生新对象。

#### IO 操作开销

IO 是**毫秒级**操作，绝不能在主线程执行。

| 操作类型                   | 近似耗时               | 备注                         |
| :--------------------- | :----------------- | :------------------------- |
| **SSD 随机读 (4KB)**      | 0.05 - 0.15 ms     | NVMe SSD，极快但仍远超 CPU 运算。    |
| **HDD 随机读 (4KB)**      | **5 - 15 ms**      | 机械寻道，一次读取 = 掉 1 帧。         |
| **文件打开 (fopen)**       | 0.1 - 1 ms         | 系统调用开销。                    |
| **小文件完整读取 (1KB)**      | 0.1 - 0.5 ms (SSD) | 文件越大越慢。                    |
| **大文件读取 (10MB)**       | **50 - 200+ ms**   | 必须异步 + 流式加载。               |
| **PlayerPrefs.Save()** | **5 - 50 ms**      | 同步写磁盘。只在关键点调用。             |
| **JSON 反序列化 (1KB)**    | 0.1 - 0.5 ms       | 取决于解析器复杂度。                 |
| **JSON 反序列化 (100KB)**  | **10 - 50 ms**     | 考虑换用 MessagePack/Protobuf。 |

> **🔴 核心原则：** 所有 IO 必须在**后台线程** + **异步回调**中执行。

#### 字符串操作开销

字符串在 C# 中是**不可变**的，每次修改都创建新对象。

| 操作                               | 近似耗时              | GC 分配         | 建议                           |
| :------------------------------- | :---------------- | :------------ | :--------------------------- |
| **短字符串拼接** `"a" + "b"`           | \~50 - 100 ns     | 是 (新对象)       | 少量可接受，循环中禁止。                 |
| **循环拼接 1000 次**                  | **1 - 5 ms + GC** | 1000 个临时对象    | 🔴 必须用 `StringBuilder`。      |
| **`StringBuilder.Append` x1000** | \~0.1 - 0.3 ms    | 预分配则无         | ✅ 正确做法。                      |
| **`string.Format`**              | \~200 - 500 ns    | 是 (boxing 可能) | 用 `$""` 插值或 `StringBuilder`。 |
| **`int.ToString()`**             | \~100 - 200 ns    | 是             | 缓存常用数字字符串 (如 "0"-"99")。      |
| **`string.Contains/IndexOf`**    | O(n) 线性           | 无             | 长字符串慎用热循环。                   |

#### 反射 (Reflection) 开销

反射是**运行时元数据查询**，极其昂贵。

| 操作                             | 近似耗时           | 对比直接调用             | 建议                         |
| :----------------------------- | :------------- | :----------------- | :------------------------- |
| **`GetType()`**                | \~5 - 20 ns    | \~1x               | 相对廉价。                      |
| **`typeof(T)`**                | \~1 ns         | 编译期确定              | ✅ 尽量用这个。                   |
| **`MethodInfo.Invoke`**        | **1 - 10 us**  | **100x - 1000x 慢** | 🔴 热路径禁止。                  |
| **`GetField/GetProperty`**     | \~100 - 500 ns | 10x - 50x 慢        | 缓存 FieldInfo/PropertyInfo。 |
| **`Activator.CreateInstance`** | **1 - 5 us**   | 50x - 200x 慢       | 用泛型工厂 `new T()` 或缓存。       |

> **替代方案：** Expression Trees 编译、Source Generators、或预生成代码。

#### 数学运算开销 (CPU)

在 CPU 上，浮点运算已非常快，但除法和超越函数仍有显著开销。

| 操作                      | 近似耗时 (Cycles) | 备注                                           |
| :---------------------- | :------------ | :------------------------------------------- |
| **加/减/乘** `+`, `-`, `*` | 1 - 3         | 极快，流水线优化。                                    |
| **除法** `/`              | **10 - 20**   | 比乘法慢 5-10 倍。用乘法替代 (如 `x * 0.5f` 代替 `x / 2`)。 |
| **平方根** `sqrt`          | 10 - 20       | 硬件指令，尚可。`rsqrt` (倒数平方根) 更快。                  |
| **三角函数** `sin`, `cos`   | **50 - 100**  | 查表或泰勒展开近似可提速。                                |
| **指数/对数** `exp`, `log`  | **50 - 100**  | 同上。                                          |
| **`Mathf.Lerp`**        | \~5 - 10      | 内部是 `a + (b-a) * t`。                         |
| **`Vector3.Normalize`** | \~20 - 50     | 包含 `sqrt`。如只需方向比较，用 `sqrMagnitude`。          |

#### 网络操作延迟

网络是**变化最大**的不确定因素。

| 操作                   | 典型延迟              | 备注               |
| :------------------- | :---------------- | :--------------- |
| **本地回环 (localhost)** | \< 0.1 ms         | 测试用。             |
| **局域网 (LAN)**        | 0.1 - 1 ms        | 理想情况。            |
| **国内跨省 (同运营商)**      | **20 - 50 ms**    | 正常延迟。            |
| **国内跨运营商**           | **50 - 150 ms**   | 可能需要加速器。         |
| **跨国 (中美)**          | **150 - 300+ ms** | 物理限制 (光速)。       |
| **DNS 查询**           | **50 - 200 ms**   | 首次连接。缓存 IP。      |
| **TCP 握手 (建连)**      | RTT x 1.5         | 约 1.5 倍往返时间。     |
| **TLS 握手 (HTTPS)**   | RTT x 2-3         | 额外 1-2 次往返。复用连接！ |

#### 线程与同步开销

多线程不是免费的午餐。

| 操作                         | 近似耗时            | 备注                        |
| :------------------------- | :-------------- | :------------------------ |
| **创建新线程**                  | **0.1 - 1+ ms** | 极其昂贵！必须用线程池。              |
| **线程池任务调度**                | 1 - 10 us       | 比创建线程快 100 倍。             |
| **`lock` (无竞争)**           | 10 - 50 ns      | 几乎免费。                     |
| **`lock` (有竞争)**           | **1 us - 数 ms** | 线程阻塞等待。减少锁粒度。             |
| **`Interlocked` 原子操作**     | 10 - 50 ns      | 无锁首选，但仍有 Cache Line 同步开销。 |
| **上下文切换 (Context Switch)** | **1 - 10 us**   | 线程过多时 CPU 疲于切换。           |
| **`Task.Run` (调度)**        | \~100 - 500 ns  | 加入线程池队列。                  |
| **`async/await` (无阻塞)**    | \~50 - 100 ns   | 状态机开销。相比同步代码略慢但可接受。       |

***

## 4. 图形预算 (Graphics/GPU Budget)

### GPU 预算 (GPU Budget)

* **Draw Calls (Batches):** \< 2000。
  * 必须启用 GPU Instancing (大量同屏怪物)。
  * UI 图集必须合并，减少 Draw Call。
* **Triangle Count:** \< 1.5M (全场景)。
  * 主角: 15k - 20k。
  * 杂兵: 1.5k - 3k (使用 LOD)。
  * Boss: 10k - 15k。
* **Overdraw:**
  * 特效粒子限制透明层数。
  * 避免全屏后处理叠加过多。

### GPU 微观基准 (Graphics Micro-Benchmarks)

以下数据为**近似值**（基于现代 PC/Console 架构），用于指导 Shader 编写。

#### Shader 指令开销参考 (GPU)

GPU 是大规模并行架构，**吞吐量 (Throughput)** 比延迟更重要。但当指令产生依赖或特定复杂运算时，开销会指数上升。

| 操作类型                  | 指令示例                        | 近似开销 (Cycles)          | 备注                                                                             |
| :-------------------- | :-------------------------- | :--------------------- | :----------------------------------------------------------------------------- |
| **基础运算**              | `+`, `-`, `*`, `madd`       | **1**                  | 现代 GPU 通常一个周期能处理 float4 的乘加。                                                   |
| **插值/透视**             | `varying` 插值                | **1-2**                | 硬件光栅化阶段处理，通常免费。                                                                |
| **倒数/平方根**            | `rcp`, `rsqrt`              | **2-4**                | 特殊功能单元 (SFU) 处理。                                                               |
| **三角函数**              | `sin`, `cos`                | **4-8**                | SFU 处理。精度要求高时更慢。                                                               |
| **复杂函数**              | `pow`, `log`, `exp`, `atan` | **8-16+**              | **昂贵**。在像素 Shader 中慎用，尽量用拟合公式近似。                                               |
| **纹理采样**              | `tex2D`, `Sample`           | **Latency: 400-800**   | 延迟极高，但 GPU 会在等待时切换线程。**依赖纹理读取**（用一次采样的结果去采样下一次）会吃满延迟，导致 GPU 停顿。                |
| **分支判断**              | `if`, `loop`                | **1 - ???**            | 如果同个 Warp/Wavefront 内所有像素走向相同分支，开销很小；如果**分歧 (Divergence)**，则两边都要执行（开销 double）。 |
| **Discard**           | `clip`, `discard`           | **Variable**           | 会破坏 Early-Z 优化，可能导致 Overdraw 暴增。                                               |
| **Normal Mapping**    | 1x `tex2D` + TBN 变换         | **+1 采样 + \~10 ALU**   | 额外一次采样 + 切线空间转换。性价比极高的细节提升。                                                    |
| **Triplanar Mapping** | **3x `tex2D`** + 混合权重       | **+3 采样 + \~20 ALU**   | 三个轴向各采样一次并混合。**开销是普通 UV 的 3 倍**，用于无 UV 展开的地形/程序化模型。可优化为 2-sample 近似。           |
| **Parallax Mapping**  | 多次 `tex2D` (步进)             | **+4-16 采样**           | 视差效果需多次深度查询。**移动端慎用**。Steep Parallax 更贵。                                       |
| **PBR (标准)**          | Albedo + Normal + MRAO      | **+3-4 采样 + \~50 ALU** | 金属度/粗糙度/AO 贴图 + BRDF 计算。现代游戏标配，但开销不低。                                          |
| **屏幕空间反射 (SSR)**      | Ray Marching                | **极高 (数百 ALU)**        | 逐像素射线步进。仅用于高端画质。                                                               |

##### 光照模型

| 光照类型                        | 计算内容                | 近似开销             | 备注                      |
| :-------------------------- | :------------------ | :--------------- | :---------------------- |
| **Unlit (无光)**              | 纯颜色/纹理              | \~5 ALU          | 最便宜，用于 UI、特效、卡通描边。      |
| **Lambert (漫反射)**           | `N·L`               | \~10 ALU         | 最简单的光照模型。               |
| **Blinn-Phong**             | Lambert + `(N·H)^n` | \~20-30 ALU      | 经典高光模型。                 |
| **GGX/Cook-Torrance (PBR)** | D + F + G 项         | **\~50-100 ALU** | 正确的物理反射。金属/粗糙度工作流。      |
| **各向异性高光**                  | 额外切线计算              | \~30-50 ALU      | 头发、拉丝金属。                |
| **SSS (次表面散射)**             | 多次采样/预积分 LUT        | **\~50-200 ALU** | 皮肤、蜡烛、树叶。实时版通常用 LUT 近似。 |
| **卡通着色 (Cel)**              | 离散化光照 + 描边          | \~20-40 ALU      | step/smoothstep 分段。     |

##### 阴影技术

| 阴影类型               | 采样次数          | 近似开销              | 备注                |
| :----------------- | :------------ | :---------------- | :---------------- |
| **硬阴影 (1x PCF)**   | 1             | +1 采样             | 锯齿明显。             |
| **软阴影 (4x PCF)**   | 4             | +4 采样 + \~20 ALU  | 常用质量档。            |
| **软阴影 (16x PCF)**  | 16            | +16 采样 + \~40 ALU | Poisson Disk 采样。  |
| **CSM (级联阴影)**     | 取决于级数         | +1-4 采样/级 + 级联判断  | 开放世界必备。远景 LOD 阴影。 |
| **Contact Shadow** | 射线步进 (4-16 步) | **+4-16 采样**      | 物体接触处的细节阴影。       |
| **PCSS (软阴影)**     | 查找 + 采样       | **极高**            | 真实半影效果，仅高端。       |

##### 环境与间接光

| 技术                   | 采样/计算            | 近似开销             | 备注              |
| :------------------- | :--------------- | :--------------- | :-------------- |
| **Cubemap 反射**       | 1x texCUBE       | +1 采样            | 简单环境映射。         |
| **Cubemap + Mip 模糊** | 1x texCUBE (LOD) | +1 采样            | 粗糙度驱动模糊，PBR 标配。 |
| **平面反射**             | 额外 RT 渲染         | **Draw Call x2** | 复制场景渲染开销！谨慎使用。  |
| **Lightmap 采样**      | 1-2x tex2D       | +1-2 采样          | 静态光照，极高性价比。     |
| **Light Probe (SH)** | 球谐计算             | \~20-30 ALU      | 动态物体间接光。无采样。    |
| **Reflection Probe** | 1x texCUBE       | +1 采样            | 局部反射探针。         |

##### 常用特效技术

| 特效                   | 实现方式          | 近似开销               | 备注                  |
| :------------------- | :------------ | :----------------- | :------------------ |
| **Fresnel (边缘光)**    | `1 - N·V`     | \~5 ALU            | 几乎免费的轮廓效果。          |
| **Rim Light (边缘高光)** | Fresnel + pow | \~10 ALU           | 增强轮廓感。              |
| **Dissolve (溶解)**    | 噪声采样 + clip   | +1 采样 + \~10 ALU   | 消融/出现效果。            |
| **UV 动画**            | 时间偏移 UV       | \~5 ALU            | 流动效果。               |
| **UV 扭曲**            | 噪声采样偏移 UV     | +1 采样 + \~10 ALU   | 热浪、水面扭曲。            |
| **顶点动画**             | VS 中偏移顶点      | \~10-30 ALU (VS)   | 旗帜、草、水面波动。便宜因为在 VS。 |
| **GPU 粒子**           | Compute/VS 模拟 | 取决于系统              | 比 CPU 粒子快 10-100x。  |
| **Outline (描边)**     | 背面挤出 / 后处理    | +1 Pass 或 \~20 ALU | 卡通渲染常用。             |

##### 高级渲染技术

| 技术                       | 开销                | 备注                      |
| :----------------------- | :---------------- | :---------------------- |
| **Tessellation**         | **极高 (硬件依赖)**     | 动态细分。移动端不支持/极慢。         |
| **Displacement Mapping** | Tessellation + 采样 | 同上 + 纹理开销。              |
| **Decal (投影贴花)**         | +1 Pass 或延迟读取     | 弹孔、血迹。Deferred 友好。      |
| **Volumetric Fog**       | **极高** (射线步进)     | 3D 体积雾。需 8-64 步，降分辨率渲染。 |
| **Bent Normal / AO**     | +1 采样             | 预烘焙数据，增强间接光遮蔽感。         |

##### 透明与混合

| 技术                        | 开销       | 备注                                |
| :------------------------ | :------- | :-------------------------------- |
| **Alpha Test (Cutout)**   | \~5 ALU  | clip/discard，Early-Z 破坏风险。树叶、铁丝网。 |
| **Alpha Blend**           | 带宽开销     | 读+写 Color Buffer。Overdraw 累积！     |
| **Premultiplied Alpha**   | 同 Blend  | 避免边缘黑边。                           |
| **Additive Blend**        | 同 Blend  | 发光、火焰。叠加更亮。                       |
| **OIT (顺序无关透明)**          | **极高**   | 多 Pass/链表。正确排序透明层。研发中技术。          |
| **Dithered Transparency** | \~10 ALU | 图案化 discard，伪透明，保留 Z-buffer。      |

#### Overdraw 与 Fill Rate：像素级性能

**Overdraw** 指同一像素被多次绘制。每多画一次，就多执行一遍 Fragment Shader。

##### 分辨率与像素数量

| 分辨率                   | 像素数量      | 备注        |
| :-------------------- | :-------- | :-------- |
| **720p** (1280x720)   | **0.92M** | 约 100 万像素 |
| **1080p** (1920x1080) | **2.07M** | 约 200 万像素 |
| **1440p** (2560x1440) | **3.69M** | 约 370 万像素 |
| **4K** (3840x2160)    | **8.29M** | 约 830 万像素 |

##### Overdraw 开销计算

假设 1080p (约 200 万像素)，Shader 每像素 50 ALU 指令：

| Overdraw 倍率       | 实际渲染像素数 | Shader 执行次数  | 相对基准        |
| :---------------- | :------ | :----------- | :---------- |
| **1x (理想)**       | 2M      | 100M ALU ops | 100%        |
| **2x (轻度)**       | 4M      | 200M ALU ops | 200%        |
| **3x (中度)**       | 6M      | 300M ALU ops | 300%        |
| **5x (严重，粒子/UI)** | 10M     | 500M ALU ops | **500%** ⚠️ |
| **10x+ (灾难)**     | 20M+    | 1B+ ALU ops  | **爆炸** 🔴   |

> **🔴 实战案例:**
>
> * **全屏粒子特效** (火焰、烟雾): 每层粒子都是一次 Overdraw。10 层粒子 = 10x Overdraw。
> * **半透明 UI 叠加**: 血条 + 技能栏 + 弹窗，每层都要混合。
> * **后处理链**: Bloom + DOF + 色调映射，每个 Pass 都是一次全屏绘制。

##### Fill Rate (填充率) 预算

Fill Rate = GPU 每秒能填充的像素数 (包含 Shader 计算)。

| GPU 档次                 | 典型 Fill Rate    | 1080p @ 60FPS 裕量             |
| :--------------------- | :-------------- | :--------------------------- |
| **GTX 1060 / RX 580**  | \~50 GPixel/s   | 2M × 60 = 120M/s → 裕量 \~400x |
| **RTX 3060 / RX 6600** | \~100 GPixel/s  | 裕量 \~800x                    |
| **移动端 (Mali-G78)**     | \~5-10 GPixel/s | 裕量 \~40-80x (极紧张!)           |

> **⚠️ 注意:** 上面是理论峰值。复杂 Shader (PBR + 多贴图) 会显著降低实际 Fill Rate。移动端尤其脆弱！

##### 带宽开销

每个像素的**显存带宽**消耗：

| 操作                           | 每像素带宽     | 1080p 全屏 (2M 像素) |
| :--------------------------- | :-------- | :--------------- |
| **读取 Color Buffer (RGBA8)**  | 4 bytes   | 8 MB             |
| **写入 Color Buffer**          | 4 bytes   | 8 MB             |
| **读取 Depth Buffer (24-bit)** | 3-4 bytes | 6-8 MB           |
| **1 张 1024x1024 纹理采样**       | 依赖 Cache  | Miss 时吃带宽        |
| **HDR Buffer (RGBA16F)**     | 8 bytes   | 16 MB            |

> **一次全屏后处理 Pass (读+写)**: 约 **16-32 MB** 带宽。
> GTX 1060 带宽 \~192 GB/s → 一帧 16.6ms 内可传输 \~3.2 GB。
> 理论上能支持 \~100 次全屏 Pass，但加上其他开销，**实际 10-20 次就是极限**。

##### 常见后处理效果开销

基于 1080p @ GTX 1060 级别的近似 GPU 时间：

| 后处理效果                   | Pass 数量 | GPU 耗时 (近似)       | 危险等级      | 备注                                 |
| :---------------------- | :------ | :---------------- | :-------- | :--------------------------------- |
| **Blit (简单拷贝)**         | 1       | 0.1 - 0.2 ms      | 🟢 廉价     | 纯带宽开销。                             |
| **Gamma/Tonemapping**   | 1       | 0.1 - 0.3 ms      | 🟢 廉价     | 每像素几条 ALU。                         |
| **FXAA**                | 1       | 0.3 - 0.5 ms      | 🟢 廉价     | 快速边缘检测 + 混合。                       |
| **SMAA (1x)**           | 2-3     | 0.5 - 1.0 ms      | 🟡 适中     | 多 Pass，效果更好。                       |
| **TAA**                 | 1-2     | 0.5 - 1.5 ms      | 🟡 适中     | 需要 Motion Vector + History Buffer。 |
| **Vignette/Film Grain** | 1       | 0.1 - 0.2 ms      | 🟢 廉价     | 几乎免费的风格化。                          |
| **Color Grading (LUT)** | 1       | 0.2 - 0.4 ms      | 🟢 廉价     | 3D LUT 查表，一次采样。                    |
| **Bloom (基础)**          | 4-6     | **1.0 - 2.0 ms**  | 🟡 适中     | 降采样 + 多级模糊 + 合成。                   |
| **Bloom (高质量)**         | 8-12    | **2.0 - 4.0 ms**  | 🟠 较重     | 更多 Mip 级别和迭代。                      |
| **景深 DOF (简单)**         | 2-3     | 1.0 - 2.0 ms      | 🟡 适中     | CoC 计算 + 模糊。                       |
| **景深 DOF (散景)**         | 4-8     | **3.0 - 6.0 ms**  | 🔴 昂贵     | 真实光圈形状需要更多采样。                      |
| **运动模糊**                | 1-2     | 0.5 - 1.5 ms      | 🟡 适中     | 依赖 Motion Vector 质量。               |
| **SSAO (简单)**           | 2-4     | **1.5 - 3.0 ms**  | 🟠 较重     | 多次深度采样。                            |
| **SSAO (HBAO+/GTAO)**   | 4-6     | **3.0 - 5.0 ms**  | 🔴 昂贵     | 高质量环境光遮蔽。                          |
| **SSR (屏幕空间反射)**        | 4-8     | **4.0 - 10.0 ms** | 🔴 **极贵** | Ray Marching + 多级模糊。移动端禁用。         |
| **体积光/God Rays**        | 4-8     | **2.0 - 5.0 ms**  | 🔴 昂贵     | 射线步进或径向模糊。                         |
| **全屏模糊 (Gaussian)**     | 2       | 0.5 - 1.0 ms      | 🟡 适中     | 分离式卷积 (H+V)。                       |
| **Kawase Blur**         | 4-6     | 0.8 - 1.5 ms      | 🟡 适中     | 比高斯更高效的迭代模糊。                       |

> **📊 典型后处理栈开销:**
>
> | 配置           | 效果组合                                   | 总 GPU 耗时             |
> | :----------- | :------------------------------------- | :------------------- |
> | **极简 (移动端)** | Tonemapping + FXAA + Vignette          | **0.5 - 1.0 ms**     |
> | **标准 (PC)**  | Bloom + TAA + Color Grading + Vignette | **2.0 - 4.0 ms**     |
> | **高端 (PC)**  | Bloom + SSAO + SSR + TAA + DOF         | **8.0 - 15.0 ms** ⚠️ |
>
> 16.6ms 帧预算下，高端后处理可能吃掉 **50-90%** 的 GPU 时间！

#### GPU Instancing 性能对比

GPU Instancing 让相同 Mesh + Material 的物体**一次 Draw Call 批量渲染**，而非逐个提交。

##### 极端场景测试 (渲染 10,000 个简单立方体)

| 方案                      | Draw Calls    | CPU 提交时间       | GPU 渲染时间 | 总帧时间                  |
| :---------------------- | :------------ | :------------- | :------- | :-------------------- |
| **无 Instancing (逐个渲染)** | **10,000**    | \~15-25 ms     | \~2-5 ms | **20-30 ms** (33 FPS) |
| **GPU Instancing**      | **1**         | \~0.1-0.3 ms   | \~2-5 ms | **2-6 ms** (166+ FPS) |
| **性能差异**                | **10000x 减少** | **50-100x 提升** | 相同       | **5-10x 总提升**         |

##### 不同物体数量的 Draw Call 对比

| 同类物体数量  | 无 Instancing | GPU Instancing | SRP Batcher |
| :------ | :----------- | :------------- | :---------- |
| 100     | 100 DC       | 1 DC           | 1-10 DC     |
| 1,000   | 1,000 DC     | 1 DC           | 10-50 DC    |
| 10,000  | 10,000 DC ⚠️ | 1 DC           | 50-200 DC   |
| 100,000 | **卡死** 🔴    | 1-10 DC        | 500+ DC     |

##### 为什么 Draw Call 这么贵？

每个 Draw Call 涉及：

1. **CPU→GPU 通信**：状态切换、缓冲区绑定 (\~5-50 us/次)

2. **驱动验证**：参数校验、着色器编译检查

3. **命令队列**：提交渲染命令到 GPU

> **经验法则:**
>
> * **Draw Call 安全上限**: PC \~2000-3000，移动端 \~200-500
> * **超过上限**: CPU 成为瓶颈，GPU 反而在等待命令

##### Instancing 使用条件

| 条件                                         | 是否支持 Instancing       |
| :----------------------------------------- | :-------------------- |
| **相同 Mesh + 相同 Material**                  | ✅ 完美支持                |
| **相同 Mesh + 不同颜色 (MaterialPropertyBlock)** | ✅ 支持                  |
| **不同 Mesh**                                | ❌ 无法合批                |
| **不同 Material**                            | ❌ 无法合批                |
| **Skinned Mesh (骨骼动画)**                    | ❌ 需 GPU Skinning 特殊处理 |
| **透明物体 (需排序)**                             | ⚠️ 部分支持，排序可能破坏批次      |

##### 实战参考 (塔防游戏场景)

| 场景内容           | 无 Instancing | GPU Instancing | 优化效果           |
| :------------- | :----------- | :------------- | :------------- |
| 200 个相同小兵      | 200 DC       | **1 DC**       | ✅ 极佳           |
| 50 种不同怪物各 10 只 | 500 DC       | **50 DC**      | ✅ 良好 (每种 1 DC) |
| 1000 颗相同子弹     | 1000 DC      | **1 DC**       | ✅ 极佳           |
| 500 个相同草丛      | 500 DC       | **1 DC**       | ✅ 极佳           |
| 100 个不同道具      | 100 DC       | 100 DC         | ❌ 无法优化         |

> **🐢 100 万次运算对比 (GPU):**
>
> * **1M 次乘加 (`x * y + z`):** 几乎瞬间完成 (受限于显存带宽或 ALU 峰值)。
> * **1M 次 `pow(x, y)`:** 比乘加慢 10-20 倍。
> * **1M 次依赖纹理采样:** 如果发生 Cache Miss，将导致 GPU 核心大量闲置等待 DRAM。

#### 模型与骨骼动画性能

##### 顶点/三角形数量开销

| 模型类型            | 推荐顶点数          | 推荐面数     | 备注                              |
| :-------------- | :------------- | :------- | :------------------------------ |
| **UI 图标/2D**    | \< 100         | \< 50    | 精灵已足够。                          |
| **粒子/子弹**       | 4-50           | 2-20     | Billboard 或简单形状。                |
| **杂兵 (大量同屏)**   | **500 - 1.5K** | 300 - 1K | 对 Instancing 友好。LOD 降至 100-300。 |
| **精英怪**         | 2K - 5K        | 1K - 3K  | 中等细节。                           |
| **Boss**        | 5K - 15K       | 3K - 10K | 可添加更多细节。                        |
| **主角 (玩家角色)**   | **10K - 25K**  | 5K - 15K | 最近距离观看，需要细节。                    |
| **环境物体 (LOD0)** | 500 - 5K       | 300 - 3K | 根据屏幕占比调整。                       |
| **地形 Tile**     | 视复杂度           | 动态 LOD   | 使用 Unity Terrain LOD 或自定义。      |

##### 全场景三角形预算

| 平台                | 目标总三角形  | 备注        |
| :---------------- | :------ | :-------- |
| **PC (GTX 1060)** | \< 1.5M | 60FPS 目标。 |
| **PC (高端)**       | \< 5M   | 可更激进。     |
| **Steam Deck**    | \< 1M   | 功耗敏感。     |
| **移动端 (高端)**      | \< 500K | 严格控制。     |
| **移动端 (中低端)**     | \< 200K | 非常严格！     |

##### 骨骼数量开销 (CPU Skinning)

每个骨骼需要**矩阵运算** + **顶点变换**，CPU Skinning 开销与骨骼数成正比。

| 骨骼数量         | CPU 开销估算 (每角色)    | 建议用途           |
| :----------- | :---------------- | :------------- |
| **1-10 骨骼**  | \~0.01 ms         | 简单道具、武器。       |
| **20-30 骨骼** | \~0.02-0.05 ms    | 基础人形怪物。        |
| **50-60 骨骼** | \~0.05-0.1 ms     | 标准人形 + 手指/面部。  |
| **100+ 骨骼**  | **\~0.1-0.3 ms**  | 复杂角色。**主角专用**。 |
| **200+ 骨骼**  | **\~0.3-1.0+ ms** | 极端情况。避免！       |

##### 同屏骨骼角色数量上限

假设目标：每帧 Skinning 总开销 \< 3ms (留给其他 CPU 工作)

| 每角色骨骼数 | CPU Skinning 上限 | GPU Skinning 上限 |
| :----- | :-------------- | :-------------- |
| 30 骨骼  | \~60-100 角色     | **500+ 角色**     |
| 60 骨骼  | \~30-50 角色      | **300+ 角色**     |
| 100 骨骼 | \~15-30 角色      | **150+ 角色**     |

> **🚀 GPU Skinning 的优势:**
>
> * 骨骼矩阵计算移至 GPU Shader
> * CPU 只需上传矩阵数据 (每角色 \~几 KB)
> * 同屏角色数可提升 **5-10x**

##### 骨骼权重 (Bones per Vertex)

每个顶点受多少骨骼影响：

| Quality 设置       | 权重数 | 开销    | 效果            |
| :--------------- | :-- | :---- | :------------ |
| **1 Bone**       | 1   | 最快    | 刚性变形，关节处有裂缝。  |
| **2 Bones**      | 2   | +50%  | 基本平滑。移动端推荐。   |
| **4 Bones (默认)** | 4   | +100% | 良好平滑。PC 标准。   |
| **Unlimited**    | 无限  | 极高    | 电影级品质。实时游戏避免。 |

##### Mesh 数据各分量开销

每个顶点的内存占用：

| 顶点属性            | 大小 (bytes)         | 备注                                |
| :-------------- | :----------------- | :-------------------------------- |
| **Position**    | 12 (float3)        | 必须。                               |
| **Normal**      | 12 (float3)        | 光照必须。可压缩为 4 bytes (packed)。       |
| **Tangent**     | 16 (float4)        | Normal Map 必须。                    |
| **UV0**         | 8 (float2)         | 主纹理。                              |
| **UV1**         | 8 (float2)         | Lightmap。                         |
| **Color**       | 4 (RGBA8)          | 顶点色。可选。                           |
| **BoneWeights** | 16-32              | 4 骨骼 = 16 bytes 索引 + 16 bytes 权重。 |
| **总计 (典型)**     | **50-80 bytes/顶点** |                                   |

##### 模型数据量示例

| 模型                    | 顶点数     | 每顶点大小    | 内存占用           |
| :-------------------- | :------ | :------- | :------------- |
| 杂兵 (1K 顶点)            | 1,000   | 60 bytes | **60 KB**      |
| 主角 (20K 顶点)           | 20,000  | 80 bytes | **1.6 MB**     |
| Boss (15K 顶点)         | 15,000  | 70 bytes | **1 MB**       |
| 100 个杂兵 (Instanced)   | 1,000   | 60 bytes | **60 KB** (共享) |
| 100 个杂兵 (非 Instanced) | 100,000 | 60 bytes | **6 MB** ⚠️    |
