目录

一图概览现代实时渲染管线

一、渲染管线概述

GPU图形管线(典型阶段)

引擎渲染管线(Unity SRP)

二、实时渲染大致流程

三、CPU端准备渲染命令

1、场景遍历

2、可见性剔除 Culling

3、排序 Sorting

4、合批 Batching

5、命令缓存 Command Buffer

四、GPU几何阶段

1、输入装配 Input Assembler

2、顶点着色器 Vertex Shader

3、细分阶段 Tessellation

4、几何着色器 Geometry Shader

5、网格着色器 Mesh Shader

6、计算着色器 Compute Shader

五、裁剪、背面剔除、视口变换

1、裁剪 Clipping

2、透视除法 Perspective Divide

3、视口变换 Viewport Transform

4、背面剔除 Backface Culling

六、光栅化

1、插值 Interpolation

2、Fragment 和 Pixel 的区别

七、片元着色器 Pixel / Fragment Shader 

八、材质系统与PBR

常见的 PBR 光照结构

九、输出合并阶段 Output Merger

1、深度测试 Depth Test

2、ZWrite

3、混合 Blending

十、向前渲染 Forward Rendering

十一、延迟渲染 Deferred Rendering 

1、GBuffer Pass

2、Lighting Pass

十二、现代管线渲染

1、Tiled Forward

2、Clustered Forward

十三、现代引擎渲染一帧包含的 Pass

1、阴影 Shadow Pass

2、深度预通道 Depth Prepass

3、不透明物体 Opaque Pass

4、贴花 Decal Pass 

5、光照 Lighting Pass

6、天空盒 Skybox / 大气散射 Atmosphere

7、透明物体 Transparent Pass

8、后处理 Post Processing

9、UI Pass

十四、HDR、Tone Mapping 与显示输出

1、HDR Render Target

2、Bloom

3、Tone Mapping

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

  1. 视锥剔除Frustum Culling: 剔除不在视角场景内的物体
  2. 遮挡剔除Occlusion Culling: 剔除被完全挡住的物体
  3. 距离剔除Distance Culling: 剔除太远的物体(LOD选择)

3、排序 Sorting

Unity引擎中Render Queue对场景中的物体分为5个大类:

  1. Background 1000
  2. Geometry    2000
  3. Alphatest     2450
  4. Transparent 3000
  5. Overlay        4000

Unity引擎中的渲染顺序:

  1. Background
  2. Opaque / Geometry(由远及近)
  3. AlphaTest
  4. Skybox
  5. Transparent(由近及远)
  6. 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

// 四维空间坐标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 中一个最基础的片元着色器代码:

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 模式:

// 正常透明度混合
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 很关键,它会读取:

GBufferDepthShadowMapLight DataReflection ProbeIBL

最终输出:HDR Scene Color。

6、天空盒 Skybox / 大气散射 Atmosphere

天空盒、体积云、大气散射通常在不透明物体附近处理。常见内容:

SkyboxProcedural SkyAtmospheric ScatteringVolumetric CloudSun DiskFog

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 输出
显示器显示                                                                                                           

Logo

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

更多推荐