现代实时渲染管线

目录

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

一、渲染管线概述

GPU图形管线(典型阶段)

[引擎渲染管线(Unity SRP)](#引擎渲染管线(Unity SRP))

二、实时渲染大致流程

三、CPU端准备渲染命令

1、场景遍历

[2、可见性剔除 Culling](#2、可见性剔除 Culling)

[3、排序 Sorting](#3、排序 Sorting)

[4、合批 Batching](#4、合批 Batching)

[5、命令缓存 Command Buffer](#5、命令缓存 Command Buffer)

四、GPU几何阶段

[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 光照结构](#常见的 PBR 光照结构)

[九、输出合并阶段 Output Merger](#九、输出合并阶段 Output Merger)

[1、深度测试 Depth Test](#1、深度测试 Depth Test)

2、ZWrite

[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)

2、Bloom

[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

  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

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 很关键,它会读取:

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 输出

显示器显示

相关推荐
threelab4 小时前
Three.js 数学函数着色器 | 三维可视化 / AI 提示词
javascript·人工智能·着色器
threelab1 天前
Three.js 3D 热力图效果 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
郝学胜-神的一滴1 天前
中级OpenGL教程 006:高光反射原理与 Shader 实现
c++·unity·godot·图形渲染·three.js·opengl·unreal
XX風2 天前
OpenGL中 为什么RBO 不能被着色器采样?
着色器
_洋2 天前
Three.js 着色器相关方法总结
开发语言·javascript·着色器
threelab5 天前
Three.js 初中数学函数可视化 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
心走7 天前
OpenGL Es渲染相机画面问题记录
opengl
小短腿的代码世界8 天前
Qt OpenGL 架构与自定义着色器:源码级解析高性能图形渲染
qt·架构·着色器
UTwelve8 天前
【UE】材质与半透明 - 01. 基于Masked遮罩的抖动半透明 DitherMask
ue5·材质·虚幻引擎·着色器