-
渲染管线(Rendering Pipeline): 是一套具体的执行流程和数据流向(比如:顶点输入 顶点着色器 光栅化 片元着色器 混合输出)。它是硬件(GPU)和图形 API 规定好的流水线。
-
渲染核心模块(图中你记录的 8 个点): 是游戏引擎或渲染器在软件架构上的子系统和功能划分。它们负责组织数据、优化裁剪,最终把准备好的数据喂给渲染管线去执行。
如果用汽车制造厂来打比方:
-
渲染管线是厂里的自动化装配流水线(车架进来 装发动机 喷漆 质检 成车出厂)。
-
渲染核心模块是厂里的各个核心管理部门(如:物流部负责资源流送、规划部负责场景组织、涂装设计部负责材质系统)。这些部门通力合作,就是为了让流水线(管线)能高效运转起来。
一、 光栅化具体是怎么做的?
传统的光栅化(Rasterization)是目前绝大多数游戏引擎(UE、Unity、Babylon.js)的核心渲染方式。它的核心任务是:把 3D 的几何模型(三角形)变成 2D 屏幕上的像素点。
具体步骤可以分为以下四个核心阶段:
[3D模型顶点] -> (1.顶点着色器) -> [2D屏幕空间三角形] -> (2.光栅化阶段/找像素) -> [片元/像素候选点] -> (3.片元着色器/算颜色) -> [最终屏幕画面]
1. 顶点着色器(Vertex Shader)
-
输入:3D 软件(如 Blender/3ds Max)导出的模型顶点数据(位置、UV、法线)。
-
操作:通过矩阵变换,把这些 3D 空间里的顶点投影到 2D 的屏幕裁剪空间上。
2. 光栅化阶段(Rasterization Stage - 硬件自动化)
-
显卡芯片会看屏幕上有哪些像素的中心点掉进了刚才投射下来的 2D 三角形里面。
-
插值(Interpolation):如果三角形的三个顶点有不同的颜色或法线,光栅化芯片会自动根据像素距离三个顶点的远近,通过重心坐标算法给夹在中间的每个像素计算出平滑过渡的法线和 UV 坐标。这些准备好的像素点在图形学里叫片元(Fragment)。
3. 片元着色器(Fragment Shader)
-
针对每个被三角形覆盖的像素点,执行一次片元着色器代码。
-
读取纹理贴图、计算光照公式,最终输出一个 RGB 颜色值。
4. 输出合并(Output Merging)
- 进行深度测试(Depth Test)。如果这个像素前面有更近的物体挡着,就把当前算的颜色丢弃;如果没有,就写入屏幕缓冲区。
一、 什么是片元着色器(Fragment Shader)?
渲染管线就是一个“从三维模型到二维像素”的流水线。
-
什么是片元(Fragment): 模型在经过顶点处理后,会被投影到二维屏幕上。GPU 会把这些几何图形(通常是三角形)切散成一个个紧密排列的小方格,准备映射到屏幕的像素上。这一个个小方格在通过“深度测试”、“剪裁”等考核、最终变成真正的屏幕“像素”之前,就叫做片元。
-
片元着色器的任务: 它的唯一核心任务就是“算颜色”。GPU 会对屏幕上准备显示的每一个片元,并行执行一次片元着色器程序。输入的是这个位置的坐标、纹理 UV、光照方向等,输出的则是这个位置的 RGBA 颜色值。
形象的比喻: 顶点着色器是“画素描线稿的”,决定物体的骨架和形状在哪里; 片元着色器是**“上色的填色工”,决定每一个格子里该涂什么颜色、怎么画出高光、阴影和质感。
二、 顶点着色器的作用是什么?
当导入一个 FBX、OBJ 模型时,这个模型本质上是由成千上万个顶点(Vertex)数据组成的集合(包含每个点的 3D 坐标、法线、UV 坐标等)。
-
运行机制: 顶点着色器(Vertex Shader)是流水线的第一步,每个顶点都会跑一次这个程序。
-
它的作用: 把模型在 3D 世界空间里的坐标,乘以各种矩阵,最终转换成在 2D 屏幕上的屏幕坐标。如果你在顶点着色器里对坐标加上噪声或者正弦波,模型就会发生形变(比如做旗帜飘动、草地随风摆动的效果)。
-
传统游戏/材质包逻辑(FBX 骨架 + 材质): 用 FBX 模型提供山脉和河流的几何形状,Shader 只需要负责贴图和光照。
-
Shadertoy 逻辑(无模型,纯数学): 屏幕上其实只有一张由两个三角形组成的扁平正方形(Quad)。网页里看到的所有高山、峡谷、水流起伏,全都是在片元着色器里用数学公式(Raymarching 算法)凭空算出来的立体视觉错觉。
Buffer
Buffer A / B / C / D(渲染缓存通道): * 这是多通道渲染(Multi-pass)的核心。常规的 Image 通道每帧画完就扔了。而如果你把 Buffer A 绑定到 iChannel0,就意味着 Image 通道可以读取上一帧 Buffer A 渲染出来的画面。
- 这在写需要“状态记忆”的特效(如流体模拟、烟雾扩散、动态模糊、全屏后处理面光源)时必不可少。
三、 什么是 Raymarching(光线步进)?
传统的渲染(如 Unreal Engine 或 Unity 的常规渲染)采用的是光栅化(Rasterization):把 3D 模型的三角形网格投射到 2D 屏幕上,然后对每个像素进行着色。
而 Raymarching 属于光线追踪(Ray Tracing)大家族的一种变体。它的核心思想是:对屏幕上的每一个像素,从摄像机发射出一条射线(Ray),这条射线不是通过复杂的数学公式直接去求交点(Classic Ray Tracing 的做法),而是像写代码走循环一样,沿着射线方向一步一步(Step by Step)向前走。
根据步进方式的不同,它主要分为两种:
-
固定步长步进(Fixed Step):每走固定距离(比如 0.1 米)就采样一次。常用于渲染雾、云、烟等没有明确边界的体渲染(Volumetric Rendering)。
-
球体追踪(Sphere Tracing / SDF Raymarching):利用符号距离函数(SDF, Signed Distance Function)。SDF 可以告诉你当前位置距离场景中最近的物体表面有多远。射线每次可以直接向前跨越这个“安全距离”,直到距离小于一个极小的阈值(比如 0.001),就判定为“命中”表面。
水体渲染实现方案对比(纯 Raymarching vs 传统光栅化管线)
| 渲染特性 / 维度 | Shadertoy (纯 Raymarching / 像素步进) 的做法 | 传统光栅化 (如 Babylon.js / 工业引擎管线) 的做法 |
|---|---|---|
| 几何形状生成 (Geometry) | 隐式数学表达 (Implicit Function) 无需显式 3D 模型。在 Fragment Shader 内通过数学公式(如多层正弦波、FFT 或噪声)定义高度场,通过射线循环步进计算出水面的高低起伏。 | 显式网格 + 纹理扰动 (Explicit Mesh) 场景中放置实际的平面网格(Grid Mesh)。通过 Vertex Shader 进行顶点位移(如 Gerstner 波),或在片元阶段使用法线贴图 (Normal Map) 扰动来表现波浪微细节。 |
| 交点/命中检测 (Intersection) | Shader 内手动求解 (Manual Traversal) 在片元着色器内运行 for/while 循环(如 Sphere Tracing),手动沿着视线方向推进,直到射线与水面函数的距离小于设定阈值。 | 硬件自动化处理 (Hardware Rasterized) 显卡固定管线自动进行三角形遍历、插值。在执行 Fragment Shader 之前,硬件已经确定了当前像素属于水面网格的哪一个位置。 |
| 折射与水深颜色 (Refraction & Absorption) | 二次光线追踪 (Secondary Ray March) 命中水面后,根据斯涅尔定律(Snell’s Law)计算折射方向,射线继续向下 Marching 寻找与河床的交点。通过两点间的绝对距离,利用比尔-朗伯定律 (Beer-Lambert Law) 计算光线衰减与吸收。 | 全屏缓冲区抓取 (Buffer Sampling) 通过前置 Pass 渲染不透明物体,在水面 Shader 中读取场景深度图 (Depth Texture) 和 不透明背景抓取纹理 (Opaque/Grab Texture)。利用 (SceneDepth - SurfaceDepth) 算出垂直水深,再套用吸光公式进行颜色混合。 |
| 反射与菲涅尔 (Reflection & Fresnel) | 追踪虚拟天空 (Virtual Ray Tracing) 根据法线计算反射射线方向。由于没有其他物体模型,通常直接将该射线代入程序化天空光数学模型(或采样 Sky CubeMap),计算虚拟撞击点的天空颜色。 菲涅尔计算公式与光栅化完全一致。 | 多方案混合反射 (Multi-source Reflection) 直接采样预渲染的环境立方体贴图 (Cube Map)、屏幕空间反射 (SSR) 或针对平坦水面的平面反射 (Planar Reflection)。 利用菲涅尔公式(如 Schlick 近似法)动态插值反射色与折射色。 |
| 抗锯齿处理 (Anti-aliasing) | 超采样抗锯齿 (SSAA) 由于纯数学边界极易产生噪点和锯齿,通常在 Shader 内部将单个像素拆分为多个子像素坐标(如 2x2 或 4x4 偏移),将整套 Raymarching 流程重复运行数遍后求平均值,计算开销极高。 | 管线级/后处理抗锯齿 (MSAA / TAA / FXAA) 依赖显卡硬件自带的多采样抗锯齿(MSAA)或引擎管线后处理阶段的临时抗锯齿(TAA)。水面片元着色器本身无需承担抗锯齿的循环计算开销。 |
| 性能特征与瓶颈 (Performance) | GPU ALU 密集型 (算力瓶颈) 完全不依赖显卡带宽和几何顶点,但对 GPU 的数学计算单元(ALU)消耗极大。当水面占据全屏或计算分支变多时,帧率会因密集循环而断崖式下跌。 | 带宽与材质填充瓶颈 (Pixel Fillrate) 计算开销相对平稳。主要瓶颈在于多 Pass 渲染时的显存带宽占用(读写深度图、抓取全屏纹理等),整体对各类硬件(包括移动端核显)的兼容性极好。 |