目录
[引擎渲染管线(Unity SRP)](#引擎渲染管线(Unity SRP))
[2、可见性剔除 Culling](#2、可见性剔除 Culling)
[3、排序 Sorting](#3、排序 Sorting)
[4、合批 Batching](#4、合批 Batching)
[5、命令缓存 Command Buffer](#5、命令缓存 Command Buffer)
[1、输入装配 Input Assembler](#1、输入装配 Input Assembler)
[2、顶点着色器 Vertex Shader](#2、顶点着色器 Vertex Shader)
[3、细分阶段 Tessellation](#3、细分阶段 Tessellation)
[4、几何着色器 Geometry Shader](#4、几何着色器 Geometry Shader)
[5、网格着色器 Mesh Shader](#5、网格着色器 Mesh Shader)
[6、计算着色器 Compute Shader](#6、计算着色器 Compute Shader)
[1、裁剪 Clipping](#1、裁剪 Clipping)
[2、透视除法 Perspective Divide](#2、透视除法 Perspective Divide)
[3、视口变换 Viewport Transform](#3、视口变换 Viewport Transform)
[4、背面剔除 Backface Culling](#4、背面剔除 Backface Culling)
[1、插值 Interpolation](#1、插值 Interpolation)
[2、Fragment 和 Pixel 的区别](#2、Fragment 和 Pixel 的区别)
[七、片元着色器 Pixel / Fragment Shader](#七、片元着色器 Pixel / Fragment Shader)
[常见的 PBR 光照结构](#常见的 PBR 光照结构)
[九、输出合并阶段 Output Merger](#九、输出合并阶段 Output Merger)
[1、深度测试 Depth Test](#1、深度测试 Depth Test)
[3、混合 Blending](#3、混合 Blending)
[十、向前渲染 Forward Rendering](#十、向前渲染 Forward Rendering)
[十一、延迟渲染 Deferred Rendering](#十一、延迟渲染 Deferred Rendering)
[1、GBuffer Pass](#1、GBuffer Pass)
[2、Lighting Pass](#2、Lighting Pass)
[1、Tiled Forward](#1、Tiled Forward)
[2、Clustered Forward](#2、Clustered Forward)
[十三、现代引擎渲染一帧包含的 Pass](#十三、现代引擎渲染一帧包含的 Pass)
[1、阴影 Shadow Pass](#1、阴影 Shadow Pass)
[2、深度预通道 Depth Prepass](#2、深度预通道 Depth Prepass)
[3、不透明物体 Opaque Pass](#3、不透明物体 Opaque Pass)
[4、贴花 Decal Pass](#4、贴花 Decal Pass)
[5、光照 Lighting Pass](#5、光照 Lighting Pass)
[6、天空盒 Skybox / 大气散射 Atmosphere](#6、天空盒 Skybox / 大气散射 Atmosphere)
[7、透明物体 Transparent Pass](#7、透明物体 Transparent Pass)
[8、后处理 Post Processing](#8、后处理 Post Processing)
[9、UI Pass](#9、UI Pass)
[十四、HDR、Tone Mapping 与显示输出](#十四、HDR、Tone Mapping 与显示输出)
[1、HDR Render Target](#1、HDR Render Target)
[3、Tone Mapping](#3、Tone Mapping)
[4、Gamma 编码](#4、Gamma 编码)
一图概览现代实时渲染管线

一、渲染管线概述
渲染管线分为两部分:
- 底层GPU图形管线:例如顶点着色器、光栅化、像素着色器;
- 上层引擎渲染管线:例如URP、HDRP、UE Deferred Renderer
可以将渲染管线理解为:把场景里的模型、材质、灯光、相机、特效,经过CPU、GPU处理,最终变成屏幕上一张图像的全过程。
GPU图形管线(典型阶段)
顶点数据
↓
输入装配 Input Assembler
↓
顶点着色器 Vertex Shader
↓
可选细分 Tessellation
↓
可选几何处理器Geometry/Mesh Shader
↓
光栅化 Rastertzation
↓
像素(片元)着色器 Fragment/Pixel Shader
↓
Depth/Stencil/Blending
↓
帧缓冲 Frame Buffer
引擎渲染管线(Unity SRP)
场景数据收集
↓
剔除 Culling
↓
阴影Shadow Pass
↓
深度测试 Depth PrePass
↓
GBuffer / Forward Opaque Pass
↓
Lighting Pass
↓
透明物体 Pass
↓
后处理
↓
UI
↓
最终显示
二、实时渲染大致流程
CPU准备
↓
GPU几何阶段
↓
光栅化
↓
像素着色
↓
光照计算
↓
后处理
↓
显示输出
三、CPU端准备渲染命令
1、场景遍历
引擎需要在场景中收集:
- 需要画哪些MeshRender(网格渲染器)/SkinnedMeshRenderer(蒙皮网格渲染器)
- 每个物体用什么Mesh、Material
- 当前相机在哪
- 有哪些灯光、阴影
- 有哪些特效、粒子、后期处理需要执行
unity中渲染一个物体需要考虑如下信息:
- Camera: 摄像机附近的才渲染
- Layer: 配合Camera的Culling Mask使用,来显示或隐藏一类物体
- Culling Mask: Camera希望或不希望看到哪一类物体
- Renderer.enabled: 物体渲染器是否开启
- Material: 用什么材质进行渲染
- Shader Pass: 这个Shader有无适合当前渲染阶段的Pass
- Render Queue: 决定什么时候渲染
2、可见性剔除 Culling
- 视锥剔除Frustum Culling: 剔除不在视角场景内的物体
- 遮挡剔除Occlusion Culling: 剔除被完全挡住的物体
- 距离剔除Distance Culling: 剔除太远的物体(LOD选择)
3、排序 Sorting
Unity引擎中Render Queue对场景中的物体分为5个大类:
- Background 1000
- Geometry 2000
- Alphatest 2450
- Transparent 3000
- Overlay 4000
Unity引擎中的渲染顺序:
- Background
- Opaque / Geometry(由远及近)
- AlphaTest
- Skybox
- Transparent(由近及远)
- Overlay / UI
4、合批 Batching
CPU提交 Draw Call 有成本,所以现代引擎会想办法合批
- Static Batching: 适合静态不动的物体,多个静态 Mesh 合并,减少 Draw Call
- Dynamic Batching: 适合小模型,但是限制较多
- GPU Instancing: 同一个 Mesh + 同一个 Material,但位置不同、颜色、参数不同。
GPU实例是技术美术最常用的一个技术,在植被、粒子、程序化生成时常用。
5、命令缓存 Command Buffer
现代引擎不会直接"立刻画",而是先记录一堆渲染命令。在现代引擎里,这些 Pass 之间的依赖越来越复杂,所以很多引擎使用 Render Graph / Frame Graph 来管理。
Render Graph的作用是自动管理:
- 哪个Pass先执行
- 哪些RenderTexture可以复用
- 哪些资源需要保留
- 哪些资源需要释放
- 哪些Pass可以异步执行
四、GPU几何阶段
CPU提交命令后,GPU开始处理顶点和几何。
1、输入装配 Input Assembler
输入装配阶段负责把顶点缓冲(Vertex Buffer)和索引缓冲(Index Buffer)组织成图元供应给后续管线。
最常见的图元是三角形(triangle),还有线(line)、点(point)。
2、顶点着色器 Vertex Shader
顶点着色器每次处理一个顶点,它的职责是坐标变换(从一个坐标系变换到另一个坐标系):
Object Space
↓ Model Matrix
World Space
↓ View Matrix
VIew Space
↓ Projection Matrix
Clip Space
常见的坐标系空间:
| 坐标空间 | 含义 | 技术美术常见用途 |
| Object Space | 模型空间 | 顶点动画、局部溶解 |
| World Space | 世界空间 | 世界坐标扫描、全局风场 |
| View Space | 相机空间 | 深度、屏幕特效 |
| Clip Space | 裁剪空间 | GPU裁剪前的位置 |
| NDC | 归一化设备坐标 | 屏幕映射 |
| Screen Space | 屏幕空间 | 后处理、描边、屏幕扭曲 |
| Tangent Space | 切线空间 | 法线贴图 |
|---|
Vertex Shader常见工作:顶点位移、骨骼蒙皮、Morph Target、风吹草动、水面波动、UV动画、顶点色读取、世界空间位置计算、法线变换
3、细分阶段 Tessellation
细分阶段可以把低面数模型在GPU上细分成更多三角形,流程大致为:
低模三角形
↓
外壳着色器 Hull Shader
↓
细分器 Tessallator
↓
域着色器 Domain Shader
↓
高密度三角形
用途:地形细分、近景石头、水面细分、位移贴图Displacement Mapping
不过在现代游戏里,传统 Tessellation 的使用比以前少了,一些场景会改用 Nanite、Mesh Shader、预烘焙高模、虚拟几何等方案。
4、几何着色器 Geometry Shader
几何着色器功能:输入一个图元,输出新的图元。例如:输入一个点,输出一个四边形。
在以前常用于:毛发、草片、粒子Billboard、法线可视化
但是Geometry Shader 性能通常不太理想,现代项目里很多场景会用 Compute Shader、Mesh Shader 或 Instancing 替代。
5、网格着色器 Mesh Shader
Mesh Shader 是更现代的几何阶段方案。DirectX 的 Mesh Shader 规范把它描述为 D3D12 中 Vertex Shader 和 Geometry Shader 的下一代替代方案,目标是提高几何管线的灵活性和性能,并且可以在光栅化前进行几何放大和剔除。
| 传统流程 | Mesh Shader | |
|---|---|---|
| 第一步 | Input Assembler | Meshlet |
| 第二步 | Vertex Shader | Amplification Shader 可选 |
| 第三步 | Geometry | Mesh Shader |
| 第四步 | Rasterizer | Rasterizer |
Mesh Shader适合:海量小三角形、GPU驱动渲染、Meshlet Culling、大规模场景、程序化几何、复杂LOD。
6、计算着色器 Compute Shader
普通shader主要服务于渲染流程,但是Compute Shader的主要作用是并行计算若干数据,例如:模拟水波、模拟粒子、生成噪声纹理、处理图像、计算布料、计算群体行为、生成程序化地形、做GPU排序。
五、裁剪、背面剔除、视口变换
1、裁剪 Clipping
位于相机近平面、远平面之外的三角形(图元)会被裁剪,裁剪发生在Clip Space。即太近的面,裁掉;太远的面。裁掉;在视锥体(四棱台)外的面,会被剔除掉。
2、透视除法 Perspective Divide
cpp
// 四维空间坐标x,y,z,w
float4 positionCS;
// 进行透视除法
float3 NDC;
NDC.x = positionCS.x / positionCS.w;
NDC.y = positionCS.y / positionCS.w;
NDC.z = positionCS.z / positionCS.w;
其中positionCS.w通常被称为齐次坐标中的其次分量,或者透视除法前的深度因子。
3、视口变换 Viewport Transform
NDC坐标范围通常是x,y∈[-1, 1],然后映射到屏幕像素Screen.x∈[0, width], Screen.y∈[0, height]。
视口变换就是一个线性映射,从[-1,1]到[0,width]和[0,height]。
4、背面剔除 Backface Culling
三角形有正面和背面,GPU根据顶点绕序判断三角形朝向,如果开启背面剔除,背对摄像机的三角形则不会渲染。
六、光栅化
光栅化是一个非常关键的阶段,它负责把三角形变成屏幕上的片元 Fragment。它将图元转换成二维图像,每个离散位置包含深度、颜色或其他属性,片元随后会被Fragment Shader处理。
1、插值 Interpolation
通过插值算法,将由若干顶点组成的图元,转换成屏幕上的像素位置。每个像素的UV、颜色、法线就是由插值得到。
在顶点着色器中直接使用的UV、法线、位置等都是从顶点阶段传过来,再被光栅化阶段插值出来。
2、Fragment 和 Pixel 的区别
Fragment 可以理解成"待处理像素",它并不是最终呈现在屏幕上的像素,因为它还要经过:
- 深度测试
- 模板测试
- Alpha Test
- Blending
- MSAA Sample 处理
所以一个Fragment 最后并不一定真实地写入屏幕。
七、片元着色器 Pixel / Fragment Shader
片元着色器决定每个片元最终输出什么颜色,它地工作通常是:
- 采样 BaseMap(基础色贴图)
- 采样 Normal Map(法线贴图)
- 采样 Metallic / Roughness / AO(金属度、光滑度、环境光遮蔽贴图)
- 计算光照
- 计算阴影
- 计算 Fresnel(菲涅尔反射)
- 计算透明度
- 输出最终颜色
如下面的代码所示,这是 Unity 中一个最基础的片元着色器代码:
cpp
float4 frag(Varyings i) : SV_Target
{
// 采样基础色贴图得到反照率
float3 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv).rgb;
// 顶点着色器采样(或计算)法线贴图传入并归一化
float3 normal = normalize(i.normalWS);
// 归一化光照方向
float3 lightDir = normalize(_MainLightDirection);
// 法线和光照方向点积
float ndotl = saturate(dot(normal, lightDir));
// 计算漫反射颜色
float3 color = albedo * ndotl;
return float4(color, 1.0);
}
八、材质系统与PBR
现代实时渲染大多使用 PBR ,也就是 Physically Based Rendering。PBR材质常见输入:
- Base Color / Albedo(基础色/反照率贴图)
- Matallic(金属度贴图)
- Roughness / Smoothness(粗糙度贴图)
- Normal(法线贴图)
- AO(环境光遮蔽贴图)
- Emission(自发光贴图)
- Alpha(透明度贴图)
核心思想:材质不再随便调一个"看起来差不多"的高光,而是用更接近物理规律的方式描述表面反射。
常见的 PBR 光照结构
一个常见地PBR BRDF可以拆解成:漫反射 Diffuse + 镜面反射 Specular,镜面反射部分通常包含:
D:Normal Distribution Fuction 法线分布函数
G:Geometry Function 几何遮蔽函数
F:Fresnel 菲涅尔项
Cook-Torrance BRDF = D * G * F / (4 * NdotL * NdotV)
九、输出合并阶段 Output Merger
Pixel Shader 算出颜色后,不是马上变成最终颜色,它还要经过 Output Merger。
Output Merger为结合 Fragment Shader 输出、Render Target 内容、Depth/Stencil Buffer 和管线状态来生成最终像素颜色的阶段,它负责深度/模板测试和混合等最终可见性与颜色合成工作。主要包括:
Depth Test
Stencil Test
Blending
Color Mask
Render Target Write
1、深度测试 Depth Test
每个像素会记录一个深度值,如果新 Fragment 比旧 Fragment 更靠近相机,就通过(近的不透明物体遮挡住远的)
Depth Buffer:
像素 A 当前深度 = 0.3
新 fragment 深度 = 0.5
因为 0.5 更远,所以被丢弃
2、ZWrite
ZWrite On 表示写入深度。
不透明物体通常:
ZWrite On
ZTest LEqual
透明物体通常:
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
透明物体如果写深度,可能会错误遮挡后面的透明层。
3、混合 Blending
透明效果需要设置 Blending 模式:
cpp
// 正常透明度混合
Blend SrcAlpha OneMinusSrcAlpha
// 柔和相加
Blend OneMinusDstColor One
// 正片叠底
Blend DstColor Zero
// 两倍相乘
Blend DstColor SrcColor
// 变暗
BlendOp Min
Blend One One
// 变亮
BlendOp Max
Blend One One
// 滤色
Blend OneMinusDstColor One
// 等价滤色
Blend One OneMinusDstColor
// 线性减淡
Blend One One
十、向前渲染 Forward Rendering
Forward Rendering 是最直观的渲染方式,流程为:
每个物体
↓
执行材质 Shader
↓
在 Shader 中计算灯光
↓
直接输出最终颜色
就是 Geometry + Material + Lighting 在同一个Pass中完成。
优点:
- 简单直观
- 对透明物体更友好
- 支持 MSAA
- 移动平台常用
- Shader 逻辑更容易理解
缺点:
- 灯光很多时成本高
- 每个物体都要处理灯光
- 多灯光时 Shader 变复杂
- 后处理和屏幕空间效果依赖额外的 Buffer
十一、延迟渲染 Deferred Rendering
Deferred Rendering 是现代主机、PC 游戏中非常常见的管线,它把"材质信息"和"光照计算"拆开。
延迟渲染的优点:
- 多灯光更友好
- 适合复杂光照(多动态点光、多聚光灯、屏幕空间反射、SSAO、Decal、延迟光照体积)
- Decal 很方便
延迟渲染的缺点:
- GBuffer 占现存和带宽
- 透明物体不好处理(多数引擎里不透明物体使用 Forward 渲染)
- MSAA支持困难
1、GBuffer Pass
先不直接算最终光照,而是把材质属性写入多张 RenderTexture,这些 RenderTexture 叫 GBuffer。
例如:
GBuffer0: BaseColor + Occlusion // 这个像素是什么材质
GBuffer1: Normal // 这个像素的法线是什么
GBuffer2: Metallic + Roughness // 这个像素有多粗糙
GBuffer3: Emission / Specular // 这个像素是不是金属
Depth: 深度 // 这个像素在世界空间的哪里
2、Lighting Pass
然后再屏幕空间做光照:
读取 GBuffer
↓
读取灯光
↓
计算每个屏幕像素的光照
↓
输出最终颜色
Deferred Shading 的核心逻辑:材质把属性写入 GBuffer,光照 Pass 再读取每像素材质属性并执行光照计算。
十二、现代管线渲染
Forward 和 Deferred 各有问题,于是现代管线常用 Forward+ 或 Clustered Rendering。
核心思想:不再让每个物体遍历所有灯光,而是先把屏幕或空间切成小块,每个小块只记录会影响它的灯光。
1、Tiled Forward
把屏幕分成很多 tile,例如 16 * 16 像素一个 tile,每个 tile 建立一个灯光列表:
Tile 0: Light 1, Light 5
Tile 1: Light 2, Light 4, Light 8
Tile 2: Light 3
然后 Pixel Shader 只遍历当前 tile 的灯光。
2、Clustered Forward
Clustered 更进一步,不只是屏幕二维切块,还加上深度方向,形成 3D cluster。同样每个 3D cluster 建立一个影响这个空间块的灯光列表。
适合:
- 大量点光
- 大量局部光
- VR
- Forward 渲染
- 透明物体光照
十三、现代引擎渲染一帧包含的 Pass
一个比较典型的现代实时渲染帧包含以下结构:
1、阴影 Shadow Pass
先从灯光视角渲染场景深度得到 Shadow Map。然后 Main Camera 渲染时查询,当前像素在灯光视角下是否被遮挡住,如果被遮挡住,就是阴影。
Shadow Map 不是颜色图,它本质上是一张深度图,记录每个在该光源视角下,每一个像素位置离得最近的片元的距离。
主相机渲染的时候,如果当前片元到灯的深度 > Shadow 中记录的深度,说明它被其他物体挡住了。
常见的阴影技术:
- Shadow Mapping
- Cascaded Shadow Maps,级联阴影
- PCF,Percentage Closer Filtering
- VSM,Variance Shadow Map
- Contact Shadow
- Ray Traced Shadow
2、深度预通道 Depth Prepass
Depth Prepass 会先只画深度,不算复杂颜色。先记录 Depth,后面正式渲染时,被遮挡像素可以提前丢弃。
适合:
- 像素 Shader 很复杂
- 场景 Overdraw 很高
- 有大量复杂材质
但它也会多一次几何绘制,所以并不是任何场景都一定划算。
3、不透明物体 Opaque Pass
不透明物体通常最先正式渲染:
Forward 管线:Opaque Pass 直接输出颜色
Deferred 管线:Opaque Pass 写入 GBuffer
4、贴花 Decal Pass
贴花用于:弹孔、血迹、污渍、路面标线、墙面破损、水迹等。
Deferred 中 Decal 可以修改 GBuffer:BaseColor、Normal、Roughness、Metallic等Render Texture。
Forward 中 Decal 通常需要额外方案,比如投影、Mesh Decal、DBuffer 等。
5、光照 Lighting Pass
在 Deferred 管线中,Lighting Pass 很关键,它会读取:
GBuffer 、Depth 、ShadowMap 、Light Data 、Reflection Probe 、IBL
最终输出:HDR Scene Color。
6、天空盒 Skybox / 大气散射 Atmosphere
天空盒、体积云、大气散射通常在不透明物体附近处理。常见内容:
Skybox 、Procedural Sky 、Atmospheric Scattering 、Volumetric Cloud 、Sun Disk 、Fog
7、透明物体 Transparent Pass
透明物体通常晚于不透明物体渲染,例如:
水、玻璃、烟雾、粒子、能量盾、半透明UI、魔法特效
透明物体难点:
1、排序问题
2、深度写入问题
3、多层混合问题
4、折射问题
5、阴影问题
8、后处理 Post Processing
后处理是在整张屏幕图像上做效果,输入通常是:
Scene Color、Depth Texture、Normal Texture、Motion Vector、Exposure
常见后处理:
Bloom、Tone Mapping、Color Grading、Vignette、Depth of Field、Motion Blur、SSAO、SSR、TAA、FXAA、Film Grain、Chromatic Aberration
9、UI Pass
最后画 UI,通常 UI 不受场景光照影响:
Scene
↓
PostProcess
↓
UI
↓
Final Present
十四、HDR、Tone Mapping 与显示输出
现代渲染通常不是直接输出 0 到 1 的颜色,场景内部一般使用 HDR。例如:
太阳高光 = 15.0
灯光反射 = 8.0
普通墙面 = 0.8
这些值超过 1,普通显示器不能直接显示,所以需要 Tone Mapping。
1、HDR Render Target
场景颜色可能存储在:
RGBA16F
R11G11B10F
RGBA32F
这些格式可以表示超过 1 的亮度。
2、Bloom
Bloom 会提取高亮区域,然后模糊,再叠回原图:
Scene Color
↓
Bright Pass
↓
Blur
↓
Add Back
3、Tone Mapping
Tone Mapping 把 HDR 映射到显示器能显示的范围,例如:
HDR 0 ~ 20
↓
Tone Mapping
LDR 0 ~ 1
最常见的 Tone Mapping:
Reinhard、ACES、Filmic、Custom Curve
4、Gamma 编码
现代 PBR 渲染通常在线性空间中计算光照,然后输出到显示器时进行 gamma 编码。大致流程为:
sRGB 贴图
↓ 解码到 Linear
在线性空间计算光照
↓ Tone Mapping
↓ Gamma / sRGB 输出
显示器显示