[图形渲染]讲透RenderTarget 第二章:为什么需要 RenderTarget

张开发
2026/5/23 12:36:40 15 分钟阅读
[图形渲染]讲透RenderTarget 第二章:为什么需要 RenderTarget
欢迎新朋友点赞、关注、收藏三连。第二章为什么需要 RenderTarget一句话概括RenderTarget 让画和看解耦——你可以先画到草稿纸上加工后再贴到屏幕。生活类比拍电影不是一镜到底需要多台摄像机、多条胶片分别拍最后剪辑合成。⏱ 30 秒概览如果 GPU 只能画到屏幕后缓冲、不能离屏渲染那么后处理模糊/Bloom/色调映射、阴影贴图、反射、延迟渲染、分屏/小地图、UI 隔离——全部做不了。离屏 RT 的核心价值是把渲染和显示解耦先画到 RT草稿再加工、合成到屏幕。这使得现代渲染管线从单通道直出变成多 Pass、多 RT 的流水线。每一个 Pass 读前一步的 RT、写下一步的 RT形成一条 RT 链——这条链就是整个渲染管线的骨架。2.1 如果只有一块屏幕高级效果无从谈起假设 GPU 只有一个地方可以画——就是屏幕的后缓冲。不能离屏渲染没有中间缓冲区。你能做什么你只能把场景中的所有物体画一遍直接输出到屏幕。颜色是什么就是什么不能再修改。然后你想实现一个全屏模糊效果。你会发现做不了。为什么因为模糊需要读取周围的像素来计算平均值。但你正在画的就是屏幕本身——你不能一边写入一个像素一边读取旁边的像素因为旁边的像素可能还没画呢。就算画了你读到的可能是新画的值也可能是旧值结果完全不可预测。这就是没有 RenderTarget 的世界你只能画一遍不能加工不能回头看不能先存后用。所有需要先画一遍然后对画出来的东西做点什么的效果都需要 RenderTarget。而这类效果在现代渲染中占了压倒性比例。2.2 后处理的起源——先画到草稿纸再加工贴到屏幕后处理Post-Processing是 RenderTarget 最直觉的应用。所谓后处理就是在场景画完之后对整个画面做额外的加工。就像拍照之后加滤镜——照片场景渲染结果是一回事滤镜后处理效果是另一回事。经典的后处理效果效果怎么做需要 RT模糊Blur对画面每个像素取周围像素的加权平均✅ 需要先画到 RT然后从 RT 读取泛光Bloom提取高亮区域 → 模糊 → 叠加回原画面✅ 需要多张 RT提取/模糊/合成色调映射Tone Mapping把 HDR 颜色映射到 SDR 范围✅ 场景先画到 HDR RT再映射景深DOF根据深度模糊远/近处✅ 需要颜色 RT 深度 RT运动模糊Motion Blur根据运动向量拉伸像素✅ 需要颜色 RT 速度 RT调色/LUT对画面整体调色✅ 需要先画到 RT后处理的基本流程永远是场景渲染 → [离屏 RT] ↓ 后处理 Pass 1 [中间 RT] ↓ 后处理 Pass 2 [中间 RT] ↓ 最终 Pass [后缓冲 / 屏幕]每一步后处理 Pass都是读取上一步的 RT 作为纹理 → 执行 Shader → 写入下一个 RT。这就是一条 RT 链。没有 RenderTarget后处理就不存在。2.3 阴影、反射、折射——需要从别的角度再画一遍有些效果不是加工画面而是需要从另一个视角再画一遍场景。阴影映射Shadow Mapping阴影映射的核心思路站在光源的位置看一遍场景记录每个像素到光源的距离深度。然后正常渲染时把每个像素的位置投影到光源视角比较深度——如果当前像素比记录的深度更远说明它被遮挡了就是阴影。关键操作从光源视角渲染一遍场景输出一张深度 RTShadow Map。光源视角渲染 → [深度 RT Shadow Map] ↓ 当纹理读取 摄像机视角渲染对每个像素查 Shadow Map → 判断阴影平面反射Planar Reflection水面反射、地板反射——怎么做把摄像机翻转到水面/地板下方从反射角度再画一遍场景结果存到一张 RT 里。然后在渲染水面时把这张 RT 作为反射纹理采样。反射摄像机渲染 → [反射 RT] ↓ 正常渲染水面时采样 [反射 RT]折射类似反射但用不同的视角/变换。有时也用屏幕空间的颜色 RT 加扭曲 UV 来近似。传送门Portal游戏中的传送门效果——一个门里面看到另一个场景。本质就是从门后面的视角渲染一遍存到 RT然后把 RT 贴到门的表面。所有这些效果都有一个共同模式用不同的摄像机/变换矩阵再画一遍场景输出到不同的 RT。2.4 延迟渲染——一次画出多张信息图延迟渲染Deferred Rendering是 RenderTarget 用量最密集的技术之一。传统的前向渲染Forward Rendering画每个物体时直接计算光照输出最终颜色。每个物体需要知道所有影响它的光源光源越多性能越差。延迟渲染换了个思路第一步G-Buffer Pass画每个物体时不算光照。只把物体的属性信息分别画到多张 RT 上RT0BaseColor基色RT1Normal法线RT2Metallic Roughness金属度 粗糙度RT3深度这组 RT 统称G-BufferGeometry Buffer。第二步Lighting Pass用一个全屏 Shader 读取 G-Buffer 的所有信息逐光源计算光照输出最终颜色。物体渲染不算光照 → [RT0: BaseColor] → [RT1: Normal] ← 这就是 MRTMultiple Render Targets → [RT2: Metal/Rough] → [Depth] ↓ 全屏光照 Pass读取所有 RT → [最终颜色 RT] → [后缓冲]延迟渲染的核心优势光照计算次数与物体数量无关只与像素数量相关。100 盏灯照 1000 个物体没关系G-Buffer 只画一遍光照只算 100 次/像素。但代价是需要大量 RT 来存储 G-Buffer。4 张 1080p 的 RGBA16F RT 4 × 1920 × 1080 × 8 bytes ≈ 63 MB。仅仅是颜色部分还没算深度。这就是为什么 RenderTarget 对性能如此关键——延迟渲染的瓶颈很大程度上就是 RT 的带宽消耗。2.5 小地图、监控、分屏——多视角需求不是所有离屏渲染都那么高级。有些非常直觉的需求也依赖 RT小地图在 RPG 或 RTS 游戏中屏幕角落的小地图需要从俯视角度渲染场景。怎么做设置一个俯视角摄像机渲染到一张小分辨率 RT比如 256×256把这张 RT 作为 UI 贴图显示在角落监控摄像头恐怖游戏中的监控画面、射击游戏中的望远镜视角——都是类似思路另一个摄像机渲染到另一张 RT。分屏多人双人分屏需要渲染两个视角到两张 RT或同一个 RT 的两半然后合成到屏幕。后视镜赛车游戏中的后视镜把后方视角渲染到一张小 RT然后贴到后视镜的模型表面。这类需求的模式非常统一不同摄像机 → 不同 RT → 合成到屏幕。简单、直观但没有 RT 就做不到。2.6 UI 独立 RT——隔离与合成现代引擎中UI 通常渲染到独立的 RT而非直接画到场景的后缓冲上。为什么分辨率隔离3D 场景可能需要动态分辨率当帧率不够时降低分辨率但 UI 文字必须保持清晰。如果 UI 和场景画在同一个 RT 上UI 文字也会变糊。把 UI 画到独立 RT分辨率始终保持原生比如 1080p最后和可能是半分辨率的场景 RT 合成到一起。后处理隔离Bloom泛光、DOF景深等后处理不应该影响 UI——你不会想看到 UI 文字发光或模糊。把 UI 画到独立 RT在后处理之后再叠加就能避免这个问题。像素格式隔离3D 场景可能用 RGBA16FHDR 格式UI 只需要 RGBA8SDR 格式。独立 RT 意味着 UI 不用付出 HDR 格式的带宽代价。3D 场景 → [场景 RT (RGBA16F)] ↓ 后处理 [后处理 RT (RGBA16F)] ↓ Tone Mapping [LDR RT (RGBA8)] ↓ UI RT 合成 [后缓冲] UI 渲染 → [UI RT (RGBA8)] ──────┘2.7 核心洞察RenderTarget 让画和看解耦把所有场景总结一下RenderTarget 解决的根本问题是让渲染过程中的画和看在时间和空间上解耦。时间解耦先画到 RT后看采样 RT。这让后处理、多 Pass 渲染成为可能。空间解耦画的地方和看的地方不一定是同一个。可以画到 512×512 的 RT但显示在 1920×1080 的屏幕上可以画到 Cubemap 的六个面但在球面上采样。视角解耦不同摄像机画到不同 RT最后合成。阴影、反射、多人分屏全靠这个。数据解耦同一次绘制可以输出颜色、法线、深度等不同数据到不同 RTMRT后续分别使用。如果没有 RenderTargetGPU 只能做一遍画完直接输出到屏幕的事情。这基本上把我们带回了上世纪 90 年代末的渲染水平——没有后处理、没有动态阴影、没有延迟渲染、没有反射探针。可以毫不夸张地说RenderTarget 是现代实时渲染的基础设施就像内存是程序运行的基础设施一样。本章小结应用场景RT 角色关键特征后处理存储场景渲染结果供后续加工多 Pass 链式处理阴影映射从光源视角存储深度信息不同视角渲染反射/折射从反射视角渲染场景不同视角渲染延迟渲染同时输出多张信息图G-BufferMRT小地图/监控/分屏不同摄像机的渲染结果多视角UI 独立隔离分辨率、后处理、格式合成 思考题如果一个游戏只使用前向渲染、不做任何后处理、不做阴影它还需要离屏 RT 吗能列出仍然需要 RT 的场景吗画和看的解耦在 Web 前端的 Canvas / OffscreenCanvas 中有没有类似的体现第 2.7 节提出了四种解耦时间/空间/视角/数据。能否想出一种全新的 RT 应用场景同时利用四种解耦下一章我们深入 RenderTarget 的生命周期——从创建到销毁每个阶段都发生了什么。你会发现RT 最容易出 Bug 的环节不是画而是状态转换——漏了一个 Barrier就是一个小时的 Debug。

更多文章