
1. 渲染流水线基础从CPU到GPU的协作在计算机图形学中渲染流水线是生成3D场景到2D屏幕图像的核心处理流程。作为开发者理解这个流水线的工作机制对于编写高效Shader和优化渲染性能至关重要。整个流程可以划分为两个主要阶段CPU端的准备工作与GPU端的图形处理。1.1 CPU端的三大准备工作在CPU端我们需要完成三个关键步骤来启动渲染流程数据加载阶段这是整个渲染流程的物质基础。我们需要将模型数据顶点坐标、法线、UV等、纹理贴图、材质参数等从硬盘加载到系统内存然后再将GPU需要直接处理的部分上传到显存。这里有个重要细节现代GPU通常有自己的独立显存与系统内存通过PCIe总线连接因此数据上传需要考虑带宽限制。实际开发中我通常会使用批处理技术减少DrawCall次数比如将多个小纹理合并为一张大纹理图集Texture Atlas这样能显著减少显存占用和数据传输开销。渲染状态配置这相当于告诉GPU如何画的说明书。包括但不限于使用哪个顶点着色器和片元着色器程序材质属性漫反射颜色、高光强度等光源参数位置、颜色、衰减等混合模式透明物体的叠加方式深度测试和模板测试设置DrawCall调用这是CPU向GPU发出的正式渲染指令。每个DrawCall对应一个需要渲染的图元批次通常是三角形集合。DrawCall过多会导致CPU成为瓶颈这是为什么我们需要关注批处理技术。1.2 GPU端的图形处理流水线当GPU接收到DrawCall后就会启动其高度并行化的图形处理流水线。这个流水线可以形象地理解为一条图形加工的装配线每个阶段专门处理特定的任务。现代GPU的渲染流水线大致包含以下阶段顶点处理阶段包括顶点着色器执行、曲面细分可选、几何着色器可选等图元组装与裁剪将顶点组装成三角形并裁剪掉视野外的部分光栅化阶段将连续的几何图形转换为离散的像素片段像素处理阶段包括片元着色器执行和各种测试深度、模板等输出合并将处理结果写入帧缓冲区值得注意的是现代GPU流水线并非完全固定某些阶段是可编程或可配置的这为我们实现各种渲染效果提供了灵活性。2. 顶点处理阶段深度解析2.1 顶点着色器的核心职责顶点着色器是GPU流水线的第一个可编程阶段它对输入的每个顶点独立执行。其核心任务包括坐标空间转换这是顶点着色器必须完成的基础工作。通常需要将顶点从模型空间转换到齐次裁剪空间。这个转换过程通常表示为clipPos MVP * modelPos其中MVP是模型(Model)-视图(View)-投影(Projection)矩阵的乘积。逐顶点光照计算虽然现代渲染更多使用逐像素光照但在某些性能敏感场景简单的逐顶点光照仍然有用。这包括漫反射光照Lambert模型镜面高光Phong或Blinn-Phong模型环境光贡献数据准备为后续阶段准备插值数据如纹理坐标颜色值法线向量需要转换为视图空间2.2 坐标系统转换详解理解坐标系统转换是Shader编程的基础。一个顶点在渲染过程中会经历以下坐标空间模型空间Local Space顶点在原始3D模型中的坐标世界空间World Space通过模型矩阵转换确定物体在场景中的位置视图空间View Space通过视图矩阵转换以相机为原点的坐标系裁剪空间Clip Space通过投影矩阵转换准备进行透视除法NDC空间透视除法后得到的归一化设备坐标屏幕空间Screen Space映射到实际像素位置在HLSL中典型的顶点着色器坐标转换代码如下float4 clipPos mul(UNITY_MATRIX_MVP, float4(pos, 1.0));2.3 顶点着色器的限制与优化由于顶点着色器的特性开发者需要注意无状态性顶点着色器无法保存或访问之前顶点的处理结果无创建/销毁能力不能增加或删除顶点并行执行顶点之间处理顺序不确定优化建议尽量减少顶点着色器中的复杂计算将可以预先计算的值放在CPU端计算后传入合理使用顶点着色器的输出插值功能3. 几何处理与光栅化阶段3.1 裁剪与屏幕映射裁剪阶段会剔除完全在视锥体外的图元并对部分在视锥体内的图元进行裁剪。这个阶段虽然不可编程但可以通过设置裁剪平面来影响其行为。屏幕映射将NDC坐标转换为屏幕像素坐标这个过程主要涉及从[-1,1]或[0,1] for DirectX的NDC空间到[0,width]×[0,height]的屏幕空间映射视口变换设置可以控制这个映射关系Z值保持不变用于后续深度测试3.2 三角形设置与遍历三角形设置阶段计算三角形边界的数学表示为光栅化做准备。而三角形遍历则是实际确定哪些像素被三角形覆盖的过程这涉及覆盖测试判断像素中心是否在三角形内深度值计算通过三个顶点的深度值插值得到属性插值对纹理坐标、颜色等属性进行透视校正插值这里有个重要细节透视校正插值。由于投影变换是非线性的简单的线性插值会导致失真。正确的插值方式需要考虑透视效果通常表示为interpolated lerp(a/z1, b/z2, t) / lerp(1/z1, 1/z2, t)4. 片元处理与输出合并4.1 片元着色器的强大功能片元着色器是另一个可编程阶段负责计算每个片元的最终颜色。其核心功能包括纹理采样通过插值得到的UV坐标从纹理读取颜色fixed4 col tex2D(_MainTex, i.uv);光照计算实现各种光照模型Lambert, Phong, PBR等特效实现如法线贴图、视差映射、屏幕空间效果等4.2 逐片元操作测试与混合在片元着色器之后GPU会执行一系列测试来决定片元是否最终写入帧缓冲模板测试比较片元的模板值与缓冲区的值常用于限制渲染区域如镜子效果特殊效果如轮廓描边深度测试比较片元深度值与深度缓冲决定可见性可以配置比较函数LESS, EQUAL, GREATER等可以开启/关闭深度写入混合操作对于透明或半透明物体需要将当前片元颜色与缓冲区颜色混合// 典型的Alpha混合公式 finalColor srcColor * srcAlpha dstColor * (1 - srcAlpha)4.3 Early-Z优化技术现代GPU会尝试在片元着色器前执行深度测试Early-Z以提前丢弃不可见片元节省计算资源。但以下情况会禁用Early-Z片元着色器修改了深度值使用了discard操作如透明度测试开启了Alpha to Coverage5. 高级话题与性能优化5.1 减少DrawCall的技巧DrawCall过多是常见的性能瓶颈解决方法包括静态批处理将不会移动的物体合并为一个网格动态批处理对小网格自动合并但有诸多限制GPU Instancing对相同网格多次绘制但使用不同参数#pragma multi_compile_instancing5.2 Shader变体与关键字优化合理使用Shader变体可以平衡功能与性能使用#pragma multi_compile定义变体通过材质关键字启用/禁用功能#pragma shader_feature _NORMALMAP5.3 现代渲染管线的演进随着图形APIVulkan, DX12, Metal的发展渲染管线更加灵活可编程的管线阶段增加如网格着色器更细粒度的资源控制多线程提交命令支持在实际项目中我通常会根据目标平台选择合适的渲染路径。对于移动平台保持Shader尽可能简单而对于高端PC则可以充分利用现代GPU的特性实现更复杂的视觉效果。