【Shader基础】GPU渲染管线原理

【Shader基础】GPU渲染管线原理 一、GPU 渲染管线的全貌上面的管线图展示了从 CPU 到像素的完整流程。你可以把它想象成一条流水线数据从一端进入经过一系列处理站最终从另一端输出为屏幕上的像素。关键可以进行编辑编程的部分流程类型阶段用途可编程顶点着色器、片元着色器写代码控制这就是 “Shader” 的核心固定功能裁剪、屏幕映射、三角形设置/遍历、深度测试、混合GPU 硬件自动完成你只能通过 API 参数间接影响可选曲面细分、几何着色器、流输出特殊需求使用频率较低核心Shader 本质上就是写顶点着色器和片元着色器这两个函数其余阶段由 GPU 固定管线处理。二、不同阶段的作用1. 应用阶段 (CPU 端)剔除Culling— 摄像机看不到的东西不送去 GPU视锥体剔除、遮挡剔除排序— 透明物体需要从后往前排画家算法1不透明物体从前向后排设置渲染状态— 绑定材质、纹理、Shader然后调用Draw CallDraw Call 是性能瓶颈每次 Draw Call 都是 CPU → GPU 的一次通信。减少 Draw Call 提升性能Batch、GPU Instancing、SRP Batcher 都在解决这个问题。2.顶点着色器 (Vertex Shader)顶点着色器顾名思义逐顶点执行。一个三角形有 3 个顶点它就跑 3 次。把顶点从模型空间变换到裁剪空间通过 MVP 矩阵相乘可以把法线、UV 等数据传递给片元着色器可以做顶点动画波浪、草、旗帜飘动输入顶点位置 v.vertex、法线 v.normal、UV v.texcoord输出裁剪空间位置 SV_POSITION以及其他自定义数据// 最简单的顶点着色器v2fvert(appdata v){v2f o;o.vertexUnityObjectToClipPos(v.vertex);// MVP 变换o.uvv.texcoord;// 传递 UVreturno;}3. 光栅化Resterization光栅化是三维渲染管线中将几何图元点、线、三角形面片转换为二维离散像素点阵的核心阶段承接 MVP 变换后的归一化设备坐标完成矢量几何到栅格像素的映射是衔接几何计算与片元着色的关键流程。裁剪— 把摄像机视野外的三角形切掉只保留视锥体内的部分屏幕映射— 把 NDC 坐标 [-1,1] 映射到实际屏幕像素坐标三角形设置— 计算三角形的边界的数学方程三角形遍历— 对屏幕上每个像素判断它是否落在三角形内部。如果是就生成一个片元 (Fragment)片元 (Fragment)光栅化生成的像素级基础数据单元包含位置、深度、纹理、颜色等属性不等同于最终像素需经测试、着色后才确定最终像素值。走样与抗锯齿离散采样会产生锯齿、摩尔纹等图形畸变通过多重采样 MSAA、超采样 SSAA 等算法平滑边缘修复采样失真问题。深度插值同步插值片元深度信息为 Z 缓冲测试提供依据判定图元遮挡关系配合画家算法完成可见性筛选。片元 ≠ 像素。片元是候选像素——它有可能被后续的深度测试或模板测试丢弃。只有通过所有测试的片元才会成为最终像素。4. 片元着色器 (Fragment Shader)片元着色器逐片元执行通常可以理解为逐像素。纹理采样— 根据 UV 坐标从贴图取颜色光照计算— 计算这个像素应该有多亮输出最终颜色// 最简单的片元着色器fixed4frag(v2f i):SV_Target{fixed4 coltex2D(_MainTex,i.uv);// 采样纹理returncol;// 输出颜色}5. 逐片元操作片元着色器输出颜色后还要经过一系列测试才能写入屏幕测试作用典型用途模板测试 (Stencil Test)用模板缓冲区做遮罩描边、镜面、小地图裁切深度测试 (Depth Test)距离摄像机近的覆盖远的防止远处的物体画在近处前面混合 (Blending)新旧颜色按公式混合透明玻璃、半透明效果三、MVP 矩阵变换 — 顶点着色器的灵魂MVP变换是三维计算机图形渲染管线中核心的多级坐标映射变换体系由模型矩阵 (Model)、视图矩阵 (View)、投影矩阵 (Projection)依次级联构成作用是将三维模型的局部几何坐标逐层转换为裁剪空间坐标最终实现三维场景向二维显示平面的几何映射是三维可视化、可见性判定、透视成像的数学基础。一个顶点要显示在屏幕上需要经历这些变换模型矩阵 M— 模型自身的 position/rotation/scale 决定了它在世界中的位置观察矩阵 V— 摄像机的位置和朝向决定了我们从哪个角度看世界投影矩阵 P— 决定了是透视投影近大远小还是正交投影最终位置 P × V × M × 原始顶点坐标Unity 封装了这个操作o.vertexUnityObjectToClipPos(v.vertex);// 等价于: mul(UNITY_MATRIX_MVP, v.vertex)四、Unity Shader 代码视角看管线一个完整的 Unity Shader 把管线映射到代码结构中ShaderCustom/Simple{Properties{_MainTex(Texture,2D)white{}// Inspector 面板参数}SubShader{// 渲染设置: 队列、混合模式、剔除...Tags{RenderTypeOpaque}Pass{CGPROGRAM#pragmavertex vert// 声明顶点着色器函数名#pragmafragment frag// 声明片元着色器函数名// 这里写你的 HLSL/CG 代码// appdata → vert → v2f → frag → SV_TargetENDCG}}}对应管线关系Properties(CPU 设置参数)↓ Pass 开始 ↓ vertexshader(你写的)→ 逐顶点变换 ↓ 光栅化(GPU 固定)→ 裁剪、映射、遍历 ↓ fragmentshader(你写的)→ 逐片元着色 ↓ 深度测试混合(GPU 固定)→ 输出到屏幕五、小结与记忆要点Shader 顶点着色器 片元着色器这两个是你可以写代码控制的部分顶点着色器决定画在哪MVP 变换片元着色器决定画成什么样颜色、纹理、光照光栅化是连接两者的桥梁把三角形变成像素Draw Call是 CPU → GPU 的通信单位减少它是性能优化的重点片元 ≠ 像素片元是候选像素要过深度测试和模板测试才能成为像素先画远处物体再画近处物体让近处物体自然覆盖远处物体从而形成正确的遮挡关系。 ↩︎