[图形渲染]讲透RenderTarget 第十一章:经典效果的 RT 拓扑
第十一章经典效果的 RT 拓扑一句话概括每个高级渲染效果背后都是一张 RT 连 RT 的管道图。生活类比工厂的流水线——每道工序的产出是下道工序的原料RT 就是工序之间传递的半成品。⏱ 30 秒概览现代渲染管线的每个效果都是一张 RT 拓扑图。基础模式Ping-Pong双 RT 交替解决读写互斥。光影效果Bloom 金字塔降采样链 升采样链5~7 张 RTShadow Map 从光源视角画深度 RTCSM 用 Texture2DArray 多层SSAO 深度法线 → R8 AO → 保边模糊SSR Hi-Z Mip 链加速 Ray March。特殊视角水面反射/折射 Clip Plane 两张额外 RT画中画 多 Camera 多 RTCubemap 探针 6 面渲染 预滤波 Mip 链3D Texture RT 用于体积雾。时序效果TAA 需要跨帧保持 History RT Motion Vector RTAI UpscaleDLSS/FSR先画小 RT 再 Compute 放大。一帧轻松 20~50 张 RT、200~500 MB 显存。11.0 延迟渲染管线全图解在深入单个效果之前先看完整延迟渲染管线的 RT 拓扑全景┌──────────────────────┐ │ 场景几何体 │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ G-Buffer Pass (MRT) │ │ RT0: BaseColor RGBA8│ │ RT1: Normal RGBA8│ │ RT2: Emissive R11B10F│ │ Depth: D32F │ └──┬───────┬───────┬───┘ │ │ │ ┌────────────┘ │ └────────────┐ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌───────▼──────┐ │ Shadow Map │ │ SSAO │ │ SSR │ │ RT: D16/D32 │ │ RT: R8 │ │ RT: RGBA16F │ └──────┬──────┘ └──────┬──────┘ └───────┬──────┘ │ │ │ └────────────┬───────┘────────────────────┘ │ ┌──────▼──────┐ │ Lighting │ ← 读 G-BufferShadowAOSSR │ RT: RGBA16F│ ← HDR 场景颜色 └──────┬──────┘ │ ┌──────▼──────┐ │ Bloom │ ← 降采样链 升采样链 │ 多级 RT │ └──────┬──────┘ │ ┌──────▼──────┐ │ ToneMapping │ ← HDR → LDR │ TAA │ │ RT: RGBA8 │ └──────┬──────┘ │ ┌──────▼──────┐ │ Back Buffer │ ← 最终输出到屏幕 └─────────────┘这张图中涉及的每个 RT 节点我们都将在本章详细拆解。A 组基础模式11.1 Ping-Pong 渲染——双 RT 交替的艺术生活类比两个桶倒来倒去——从 A 桶倒到 B 桶处理后再从 B 桶倒回 A 桶。问题你不能在同一个 Pass 中同时读写同一张 RT读写互斥第 3.8 节。但很多效果需要读上一步的结果写这一步的结果——如果上一步和这一步用同一张 RT就违反了读写互斥。解法两张 RT 交替使用——奇数步读 A 写 B偶数步读 B 写 A。Pass 0: 读 Source → 写 RT_A Pass 1: 读 RT_A → 写 RT_B Pass 2: 读 RT_B → 写 RT_A Pass 3: 读 RT_A → 写 RT_B ...典型场景多迭代模糊Gaussian Blur 分两遍水平 垂直再重复流体/物理模拟每帧读上一步状态写下一步状态Bloom 链的升降采样实现要点// Unity 伪代码RTHandle[]pingpong{rtA,rtB};intsrc0,dst1;for(inti0;iiterations;i){cmd.SetRenderTarget(pingpong[dst]);cmd.Blit(pingpong[src],pingpong[dst],blurMaterial);// 交换(src,dst)(dst,src);}// 最终结果在 pingpong[src] 中注意Ping-Pong 意味着至少 2 张格式相同的 RT。在 Frame Graph 中系统可以自动识别这种模式并优化 Alias。B 组光影效果11.2 Bloom降采样链 升采样链Bloom 的 RT 拓扑是一个经典的金字塔结构⚠️行业经验早期 Bloom 实现只做一级模糊全分辨率高斯模糊结果光晕范围很小、看起来像白雾。COD: Advanced Warfare2014推广了逐级降采样升采样的金字塔结构——每降一级等效模糊半径翻倍。这种实现已成为工业标准UE4/5 和 Unity HDRP 都采用此方案。降采样时用Karis Average亮度加权平均可以抑制高亮像素的萤火虫闪烁Firefly Artifact。降采样Downsample Full (1920×1080) → Half (960×540) → Quarter (480×270) → 1/8 → 1/16 → ... 升采样Upsample 混合 1/16 → 1/8 → Quarter → Half → Full ↑ ↑ ↑ ↑ (混合降采样对应级别的结果)每一级都是一张独立的 RT。典型实现需要5~7 张不同分辨率的 RT。RT 详情级别尺寸格式用途Mip 01920×1080RGBA16F原始场景颜色亮度阈值过滤后Mip 1960×540RGBA16F半分辨率降采样Mip 2480×270RGBA16F1/4 分辨率Mip 3240×135RGBA16F1/8 分辨率Mip 4120×68RGBA16F1/16 分辨率Mip 560×34RGBA16F1/32 分辨率最低级降采样 Pass5 个 Draw CallPass 0: Blit(Mip0 → Mip1, DownsampleShader) Pass 1: Blit(Mip1 → Mip2, DownsampleShader) Pass 2: Blit(Mip2 → Mip3, DownsampleShader) Pass 3: Blit(Mip3 → Mip4, DownsampleShader) Pass 4: Blit(Mip4 → Mip5, DownsampleShader)升采样 Pass5 个 Draw Call每次混合降采样和升采样Pass 5: Blit(Mip5 Mip4 → Mip4, UpsampleShader) // Mip5 升采样后与 Mip4 混合 Pass 6: Blit(Mip4 Mip3 → Mip3, UpsampleShader) Pass 7: Blit(Mip3 Mip2 → Mip2, UpsampleShader) Pass 8: Blit(Mip2 Mip1 → Mip1, UpsampleShader) Pass 9: Blit(Mip1 Mip0 → Output, UpsampleShader) // 最终混合回全分辨率优化点用 Compute Shader 一次 Dispatch 处理多级 Mip见第 9.5 节低级别 Mip 的 RT 很小60×34带宽可忽略可以用R11G11B10F替代RGBA16F省一半带宽如果不需要 Alpha11.3 Shadow Mapping深度 RT 的创建、渲染、采样Shadow Map 是从光源视角画一遍场景的产物——输出的是纯深度 RT。┌─────────────┐ ┌────────────────┐ │ 场景几何体 │ ──────→ │ Shadow Map Pass │ │ (从光源视角) │ │ RT: Depth Only │ │ │ │ D16 / D32F │ └─────────────┘ └───────┬────────┘ │ ┌───────▼────────┐ │ Lighting Pass │ │ 采样 Shadow Map │ │ 做深度比较 │ └────────────────┘Shadow Map RT 的特点只需要 Depth不需要 Color——这是少数没有 Color Attachment的 Render Pass格式选择D16低精度但带宽小或D32F高精度自阴影精度好分辨率通常 1024×1024 ~ 4096×4096独立于屏幕分辨率PCF 采样采样 Shadow Map 时做周围像素的比较和过滤Cascaded Shadow MapCSM方向光的 Shadow Map 需要覆盖很大范围用一张 Shadow Map 精度不够。CSM 把视锥体分成多个级联Cascade每个级联一张 Shadow MapRT 方案 A一张大 Texture2D分成 4 个区域 ┌────────┬────────┐ │ Cascade0│ Cascade1│ │ 2048x2048│ 2048x2048│ ├────────┼────────┤ │ Cascade2│ Cascade3│ │ 2048x2048│ 2048x2048│ └────────┴────────┘ 总4096×4096 D16 RT 方案 BTexture2DArray4 层 Layer 0: Cascade0 (2048×2048 D16) Layer 1: Cascade1 Layer 2: Cascade2 Layer 3: Cascade3方案 B 更现代——支持 Layered Rendering一次 Draw Call 画所有级联Geometry Shader 选择层。11.4 SSAO噪声 RT 模糊 RTSSAOScreen Space Ambient Occlusion由 Crytek 在Crysis2007中首创是 RT 作为中间计算画布的经典案例。其 RT 链条[Depth RT] [Normal RT] │ ▼ ┌──────────────┐ │ SSAO Pass │ ← 采样深度和法线用随机方向做半球采样 │ 输入: Depth, │ │ Normal │ │ 输出: R8 (AO) │ ← 单通道就够遮蔽因子 0~1 └──────┬───────┘ │ ┌──────▼───────┐ │ Bilateral │ ← 保边模糊去除采样噪声 │ Blur Pass │ │ RT: R8 (AO) │ ← Ping-Pong水平模糊 → 垂直模糊 └──────┬───────┘ │ ▼ 最终 AO 纹理 → 在 Lighting Pass 中乘到环境光上RT 格式选择AO 只需要一个通道0~1 的遮蔽值→R8_UNORM最省带宽如果要半分辨率 AO常见优化→ RT 尺寸为屏幕 1/2后续升采样时注意边缘瑕疵模糊用 Bilateral保边→ 需要读深度做权重避免模糊跨越深度边缘11.5 SSRHi-Z BufferSSRScreen Space Reflection在Killzone: Shadow Fall2013, Guerrilla Games中被首次大规模工业化需要一组特殊的 RT[Depth RT] │ ▼ ┌──────────────┐ │ Hi-Z Build │ ← 生成深度纹理的 Mipmap 链 │ Pass │ 每级取 2×2 区域的最小/最大深度 │ RT: D32F Mips │ └──────┬───────┘ │ [Color RT] [Normal RT] [Hi-Z] │ ▼ ┌──────────────┐ │ SSR Trace │ ← 在屏幕空间用射线步进Ray March │ Pass │ Hi-Z 加速跳过大面积空白区域 │ RT: RGBA16F │ ← 存储反射颜色 置信度 └──────┬───────┘ │ ┌──────▼───────┐ │ SSR Resolve │ ← 去噪、填充、与场景混合 │ Pass │ │ RT: RGBA16F │ └──────────────┘Hi-Z Buffer 本质上是 Depth RT 的 Mipmap 版本——用 Compute Shader 生成见第 9.5 节每级存储一个小区域的最大深度。Ray March 时先在高 Mip 级别步进步长大检测到相交后再降到低 Mip 级别精确拟合——这就是 “Hierarchical” 的含义。C 组特殊视角与非标准形态11.6 水面反射/折射Clip Plane 两张 RT水面效果需要两张额外的场景 RT——一张存反射、一张存折射[原始场景] │ ├─────────────────────────┐ │ │ ┌───▼───────────┐ ┌───────▼───────┐ │ 反射 Pass │ │ 折射 Pass │ │ Camera 上下翻转 │ │ Camera 正常 │ │ Clip Plane 裁 │ │ Clip Plane 裁 │ │ 掉水面以下部分 │ │ 掉水面以上部分 │ │ RT: RGBA8/16F │ │ RT: RGBA8/16F │ └───────┬───────┘ └───────┬────────┘ │ │ └────────┬───────────┘ │ ┌──────▼──────┐ │ 水面 Shader │ ← 采样反射 RT 折射 RT │ 扭曲 UV │ 用法线贴图做 UV 偏移 │ 菲涅尔混合 │ 按视角权衡反射/折射比例 └─────────────┘关键细节反射 Camera 是原始 Camera 关于水面的镜像Clip Plane 确保反射只画水面以上、折射只画水面以下两张 RT 可以低分辨率比如 1/2 或 1/4——水面本身带扰动低分辨率不明显如果用 SSR 替代第 11.5 节可以省掉反射 RT但 SSR 无法处理水面以下的折射11.7 画中画 / 后视镜多 Camera 多 RT 组织赛车游戏的后视镜、FPS 游戏的瞄准镜画中画、安全摄像头画面——都是额外的 Camera 渲染到额外的 RT。Camera 0主视角 Camera 1后视镜 │ │ ▼ ▼ ┌────────────┐ ┌────────────┐ │ Main RT │ │ Mirror RT │ │ 1920×1080 │ │ 480×270 │ │ RGBA16F │ │ RGBA8 │ └─────┬──────┘ └─────┬──────┘ │ │ │ ┌────────────────────┘ │ │ ▼ ▼ ┌────────────────┐ │ 合成 Pass │ ← Mirror RT 贴到 Main RT 的某个区域 │ 输出: Back Buffer│ └────────────────┘优化要点后视镜 RT 分辨率可以很低——视觉上后视镜本身很小后视镜的场景渲染可以省略很多 Pass不需要 SSAO、Bloom 等后处理渲染频率可以降低每 2~3 帧更新一次Unreal 用SceneCaptureComponent2D天然支持这种工作流11.8 Cubemap RT 与环境探针——六面渲染的特殊工作流环境反射探针Reflection Probe需要从一个点向六个方向各渲染一张图——组成一个 Cubemap。Cubemap RT 的创建Cubemap 本质上是 6 张正方形 2D 纹理组成的一个特殊纹理┌──────┐ │ Y │ ┌────┼──────┤────┬──────┐ │ -X │ Z │ X │ -Z │ └────┼──────┤────┴──────┘ │ -Y │ └──────┘每个 Face 就是一张 RT。创建方式// DX12D3D12_RESOURCE_DESC desc{};desc.DimensionD3D12_RESOURCE_DIMENSION_TEXTURE2D;desc.Width256;desc.Height256;desc.DepthOrArraySize6;// ← 6 个 Facedesc.MipLevelsnumMips;desc.FormatDXGI_FORMAT_R16G16B16A16_FLOAT;desc.FlagsD3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;逐面渲染 vs 单 Pass 多层渲染方案 A——逐面渲染6 个 Draw Callfor face in 0..5: 设置 Camera 朝向 face 对应的方向 绑定 Cubemap 的 face 为 RT 渲染场景方案 B——Geometry Shader / Multiview 单 Pass// Geometry Shader一个三角形 → 复制到 6 层 layout(triangles) in; layout(triangle_strip, max_vertices 18) out; void main() { for (int face 0; face 6; face) { gl_Layer face; // 选择 Cubemap 的哪个 Face for (int v 0; v 3; v) { gl_Position faceViewProj[face] * gl_in[v].gl_Position; EmitVertex(); } EndPrimitive(); } }方案 B 减少了 Draw Call但 Geometry Shader 吞吐量有限大场景不一定更快。预滤波 Mipmap 链的 RT 降采样PBR 环境光需要不同粗糙度对应不同模糊程度的环境图。做法是对 Cubemap 的每级 Mip 做 GGX 预滤波Mip 0 (256×256): 原始环境图 Mip 1 (128×128): roughness ≈ 0.25 的预滤波 Mip 2 (64×64): roughness ≈ 0.5 Mip 3 (32×32): roughness ≈ 0.75 Mip 4 (16×16): roughness ≈ 1.0每级 Mip 都是一次渲染——读取上一级或 Mip 0的 Cubemap用 GGX 重要性采样做卷积写到当前 Mip 级别的 RT。共6 faces × numMips次渲染或用 Compute Shader 并行处理。实时 vs 烘焙探针实时探针烘焙探针更新频率每帧或每 N 帧编辑器中离线烘焙分辨率64~256256~1024RT 需求每帧 6 × 分辨率的 RT Draw Call无运行时 RT 开销动态物体✅ 能反射❌ 只有静态场景性能很贵相当于额外渲染 6 次场景零运行时开销11.9 非标准 RT 形态——3D Texture、2D Array、Layered RenderingVolume RT3D Texture用于体积雾 / 体积光3D 纹理就是一个立方体的体素网格。作为 RT 时Compute Shader 通过RWTexture3D写入RWTexture3Dfloat4 volumeRT : register(u0); // 例如 160×90×64 [numthreads(8, 8, 4)] void CSMain(uint3 id : SV_DispatchThreadID) { float3 worldPos voxelToWorld(id); float4 scattering computeScattering(worldPos); volumeRT[id] scattering; }后续 Pass 用Texture3D.SampleLevel做三线性插值采样。典型尺寸160×90×64体积雾分辨率远低于屏幕——因为雾的频率很低不需要高分辨率。注意3D RT 不走光栅化管线——没有 ROP 支持直接写 3D 纹理。必须用 Compute Shader 或 Layered Rendering。Texture2DArray RTCascaded Shadow Map / Point Light ShadowTexture2DArray 是一组 2D 纹理层叠每层尺寸相同可以作为 RT 的不同层。用途Cascaded Shadow Map4 层每层一个级联Point Light Shadow6 层Cubemap 用 TextureCubeArray 或 Texture2DArray × 6多光源 Shadow Atlas多层不同光源占不同层或不同区域Layered Rendering一次画多层通过 Geometry Shader或 Vulkan/DX12 的 Multiview在一次 Draw Call 中把图元分发到 Texture2DArray 的不同层// Geometry Shader 选择输出到哪一层 gl_Layer cascadeIndex;或在 DX11 中用SV_RenderTargetArrayIndexstruct GSOutput { float4 pos : SV_Position; uint layer : SV_RenderTargetArrayIndex; // ← 指定输出层 };这避免了为每层单独做一次 Draw Call减少了 CPU/GPU 的 Draw Call 开销。但 Geometry Shader 有吞吐量瓶颈——现代做法更倾向于 Mesh Shader 或 Multiview。D 组时序与分辨率11.10 TAA 的 RT 工作流——历史帧、Motion Vector、Temporal 累积TAATemporal Anti-Aliasing从根本上改变了 RT 的使用模式——它需要跨帧保持 RT 的内容。为什么需要保留上一帧的 RT传统渲染中每帧所有 RT 都可以在帧结束后丢弃。但 TAA 需要当前帧的颜色 RT上一帧的颜色 RT历史帧通过混合当前帧和历史帧TAA 实现了超采样效果每帧 Jitter 半像素累积多帧等效于超采样。帧 N-1 [Scene Color N-1] → 存入 [History RT] 帧 N [Scene Color N] [History RT (帧N-1)] [Motion Vector RT] → TAA Resolve → [New History RT] [TAA Output] [New History RT] 变成帧 N1 的 [History RT]这里有个关键History RT 不能被 Pool 回收——它必须一直存在跨帧保持数据。这是和所有 Transient RT 不同的地方。Motion Vector RT 的生成与采样Motion Vector运动矢量记录每个像素从上一帧到当前帧的屏幕空间位移Motion Vector RT 格式RG16F 或 RG16_SNORM R 水平位移像素单位 G 垂直位移像素单位生成方式在 G-Buffer Pass 中额外输出一个 MRT——// 当前帧的 clip space 位置 float4 clipPos mul(viewProj, worldPos); // 上一帧的 clip space 位置用上帧的 viewProj float4 prevClipPos mul(prevViewProj, prevWorldPos); // 转到 NDC float2 screenPos clipPos.xy / clipPos.w * 0.5 0.5; float2 prevScreenPos prevClipPos.xy / prevClipPos.w * 0.5 0.5; // Motion Vector 当前位置 - 上一帧位置 motionVector screenPos - prevScreenPos;TAA Resolve 时用 Motion Vector 反向查找历史帧中对应的像素float2 historyUV currentUV - motionVector; float4 historyColor HistoryRT.Sample(sampler, historyUV);历史颜色的 Clamp / Clip 策略直接混合历史帧和当前帧会出现严重的拖影Ghosting——当物体快速运动或出现遮挡变化时历史帧的颜色可能完全错误。解法用当前帧局部像素的颜色范围来约束历史颜色// 采集当前像素 3×3 邻域的颜色 float4 neighborMin, neighborMax; for (int y -1; y 1; y) for (int x -1; x 1; x) { float4 c CurrentColor.Sample(..., uv float2(x,y) * texelSize); neighborMin min(neighborMin, c); neighborMax max(neighborMax, c); } // 把历史颜色 Clamp 到邻域范围内 historyColor clamp(historyColor, neighborMin, neighborMax); // 混合 float4 result lerp(historyColor, currentColor, 0.05); // 通常 5%~10% 当前帧Clamp直接钳制到 AABBvsClip沿射线到 AABB 最近表面——Clip 产生更少的瑕疵但计算略贵。从 MSAA 到 TAA——RT 使用模式的根本变化维度MSAATAART 大小× N每像素 N 个 sample不增加但需要额外的 History RT Motion Vector RT时序需求单帧多帧跨帧保持 History RT适用管线Forward延迟渲染与 MSAA 矛盾Forward Deferred 均可画面质量边缘硬朗略微柔化可接受性能显存 ×N、带宽 ×N额外 1~2 张全分辨率 RT Resolve 开销TAA 已成为现代游戏的默认选择详见第 8.7 节为什么业界从 MSAA 转向 TAA。11.11 超采样、降采样与 AI Upscale——RT 分辨率游戏的三种玩法SSAA先画大再缩小——最暴力的 RT 用法Super Sampling Anti-Aliasing以 2× 或 4× 分辨率渲染然后 Downsample 到目标分辨率。Scene RT (3840×2160) → Resolve/Downsample → Output (1920×1080)质量最好但 RT 大小是 4 倍4K带宽、显存、着色量全部 4 倍。现代游戏几乎不用。FSR / DLSS / XeSS 的输入输出 RT 链条——先画小再放大与 SSAA 完全相反的思路以低于目标分辨率渲染用 AI 网络放大。Scene RT (低分辨率, 如 1280×720) Motion Vector RT (低分辨率) Depth RT (低分辨率) [DLSS: 额外的 Exposure RT] │ ▼ ┌──────────────────┐ │ UpscalerCompute│ ← FSR 2 / DLSS / XeSS │ 读取: 低分辨率场景 Motion Vector Depth History │ 输出: 高分辨率颜色 └──────────┬───────┘ │ ▼ Output RT (原生分辨率, 如 1920×1080 或 3840×2160)RT 关键细节场景渲染的所有 RT 都是低分辨率G-Buffer、Shadow Map、SSAO 等都跟着缩小Upscaler 的输出 RT 是原生分辨率Upscaler 需要自己的History RT类似 TAA后处理链Bloom、色调映射等可以在低分辨率或高分辨率做——取决于管线设计与动态分辨率的关系动态分辨率第 10.5 节控制的是以什么分辨率渲染AI Upscale 控制的是输出什么分辨率。两者常常结合动态分辨率决定当前帧以 60% 渲染 → Scene RT 1152×648 → AI Upscale → Output RT 1920×1080 帧率恢复后改为 80% 渲染 → Scene RT 1536×864 → AI Upscale → Output RT 1920×1080RTHandle 系统第 10.5 节为这种模式提供了基础——RT 大小固定为最大1920×1080Viewport 跟随动态分辨率缩放。本章小结本章覆盖的 RT 拓扑汇总效果RT 数量关键 RT 格式性能敏感度Ping-Pong2与源 RT 相同低Bloom5~7RGBA16F / R11G11B10F中低 Mip 很小Shadow Map1~4D16 / D32F中SSAO2~3R8低可半分辨率SSR2~3 Hi-Z MipsRGBA16F D32F高水面反射/折射2RGBA8/16F中画中画1 per CameraRGBA8低低分辨率即可Cubemap 探针6 Faces × MipsRGBA16F高实时/ 零烘焙3D Texture雾1RGBA16F低分辨率很低TAA2History Current MVRGBA16F RG16F中AI Upscale2~3RGBA16F中核心洞察现代游戏一帧中轻松用掉 20~50 张 RT总显存可达 200~500MB。Frame Graph第 10.6 节的 RT 自动管理不是锦上添花——是必需品。 思考题画一张你正在开发或正在玩的游戏/应用的完整 RT 拓扑图。标注每张 RT 的格式、尺寸倍率和生命周期范围。Bloom 的降采样链使用了 5~7 级 Mip——如果只用 2 级视觉效果会怎样如果用 10 级呢这背后的数学原因是什么TAA 需要跨帧保留 History RT。如果玩家突然快速转头帧间运动极大TAA 会出现什么问题DLSS/FSR 是怎么缓解的下一章讲如何优化这些 RT 的性能开销。你刚看到的 20~50 张 RT 拓扑图每张都在读写存——不优化的话光带宽一项就能把 GPU 喂满。我们将用一套系统化的方法论从格式瘦身、分辨率缩放到 Memory Aliasing把这些 RT 的开销砍到最佳平衡点。实践篇回顾第八到第十一章完成了怎么用 RT的四层递进——用 MRT 一次画多张第 8 章、用 Compute 自由读写第 9 章、用 Frame Graph 自动管理第 10 章、用拓扑图串联 20 种效果第 11 章。接下来的精通篇回答最后三个问题怎么让它跑得快第 12 章、坏了怎么修第 13 章、以及未来往哪走第 14 章。