67.性能优化-GPU-影响因素-顶点和片元
67.1 知识点
顶点和片元的基本概念
顶点
顶点一般指模型的几何数据,是组成三角形网格的点。
一个 3D 模型实际上就是由很多三角形拼接而成的,而三角形的角就是顶点。
作用:
是网格的框架点,决定了模型的形状。
着色器阶段:
一般会在着色器中的顶点着色器中进行处理和计算。
顶点着色器主要任务:
- 将模型空间的顶点转换到裁剪空间、屏幕空间。
- 把需要的数据(UV、法线、颜色等)传递给片元阶段。
片元
片元一般指光栅化阶段产生的、候选的像素点。
当三角形被投影到屏幕后,会覆盖一片像素区域。每个像素位置对应一个片元,GPU 会为它准备一份数据(位置、UV、颜色等)。
作用:
决定屏幕上每个像素的最终颜色。
着色器阶段:
一般会在着色器中的片元着色器中进行处理和计算。
片元着色器主要任务:
- 计算像素颜色(光照、材质、纹理采样)。
- 执行深度测试、混合、透明处理。
- 最终写入帧缓冲,形成屏幕像素。
通俗理解
- 顶点:就像建房子的”钢筋骨架”。
- 片元:就是把框架之间的”砖块”一块块填上。
GPU 渲染时:先有骨架(顶点),再填满砖块(片元),最后变成完整画面。
为什么顶点和片元会影响性能
顶点方面
由于顶点数据需要进行计算,以下因素会影响性能开销:
- 模型的顶点数越多,计算量越大
- 高顶点数模型,如未优化的高模、过密网格。
- 复杂骨骼蒙皮,需要大量骨骼权重计算。
- 复杂的顶点着色器逻辑会放大开销
比如顶点动画(流体波动、噪声扰动、形变等)。
片元方面
由于片元数据需要进行计算,以下因素会影响性能开销:
- 分辨率和覆盖率
片元数直接与屏幕分辨率和绘制面积成正比。- 屏幕分辨率越高,片元数就越多,计算消耗就越大。
- 全屏效果(后处理、屏幕空间特效)通常直接消耗片元性能。
- 过度绘制(OverDraw)
一个像素被多个物体反复覆盖计算。 - 高开销片元运算
复杂的片元着色器逻辑(多层纹理采样、分支、循环、PBR、阴影采样、SSR、体积雾、全屏后处理)非常吃性能。
顶点和片元的优化思路
顶点优化
顶点的主要优化思路就是从本质上减少顶点以及顶点相关的计算。
1. 降低顶点数
- LOD:根据距离切换不同精度的模型。
- 网格简化:减少不必要的顶点。
- 优化远距离对象:使用 Impostor(替身)技术,包括:
- Billboard(广告牌)
- 多角度烘焙(在球面或半球面上采样多个角度,把结果打包到一张大纹理图集)
- Octahedral Impostor(八面体编码,把球面角度映射到 2D 纹理,通过一种高效编码方式存储多角度外观)
2. 蒙皮优化
减少骨骼数量、减少顶点权重、合并骨骼等。
3. 顶点动画
把复杂的程序形变改为 VAT(顶点动画纹理),能贴图查表就别每帧算噪声。
VAT(Vertex Animation Texture,顶点动画纹理):把复杂的顶点动画(顶点位置/法线随时间变化)预先烘焙进贴图里,在运行时通过 Shader 从贴图中查表来驱动顶点,而不是实时在 CPU 或 GPU 上做骨骼/物理计算。
4. 顶点着色器输出精简
减少 v2f 里插值数(TEXCOORD 通道),避免为片元传一堆用不到的数据。
5. 顶点着色器精度和数学
- 移动端着色器中数值类型尽量用
half。 - 避免大量
sin/cos/pow。 - 能自己写计算过程,就别调用自带的一些高开销函数,比如:
pow(x, 2.0)→x * x。 - 把复杂函数结果预计算在纹理里,运行时只采样。
6. 合批处理
使用各批处理技术,减少 DrawCall。
7. 剔除先于变换
使用遮挡剔除、视锥剔除,减少要处理的内容。
片元优化
片元的主要优化思路就是从本质上减少片元以及片元相关的计算。
1. 降低分辨率
动态分辨率、注视点渲染等。
2. 降低片元工作量
- 尽量减少纹理采样次数与层数(合并贴图通道、使用贴图图集)。
- 片元着色器中减少循环/分支语法的使用。
- 把复杂函数结果预计算在纹理里,运行时只采样。
- 减少 OverDraw。
3. 减少全屏 Pass
- 屏幕后处理中,能半分辨率就半分辨率。
- 将多种屏幕后处理效果合并在一个 Pass 中处理。
4. 避免 Early-Z(提前深度测试)失效
比如透明测试就会导致其失效。
5. Shader 分支收敛
尽量不要使用 if / else 语法,可以用一些函数替代。
// 原始分支写法
if (mask > 0.5) color = a; else color = b;
// 用插值函数替代
color = lerp(b, a, step(0.5, mask));
6. 光照和阴影
降低光照和阴影质量,光照能用逐顶点就别用逐片元。
7. 合理使用 Mipmap 功能
注意事项
在开发时注意这些优化点,可以减少性能问题的发生。
当发生性能问题时,先定位问题再针对性解决问题,结合性能分析窗口、帧调试窗口来分析定位问题,不要凭感觉。
67.2 知识点代码
Lesson67_性能优化_GPU_影响因素_片元和顶点.cs
public class Lesson67_性能优化_GPU_影响因素_片元和顶点
{
#region 知识点一 顶点和片元的基本概念
//顶点和片元如果单独理解
#region 顶点
//一般指模型的几何数据,是组成三角形网格的点
//一个 3D 模型实际上就是由很多三角形拼接而成的,而三角形的角就是顶点
//作用:
//是网格的框架点,决定了模型的形状
//着色器阶段:
//一般会在着色器中的 顶点着色器 中进行处理和计算
//顶点着色器 主要任务
//1.将模型空间的顶点转换到裁剪空间、屏幕空间
//2.把需要的数据(UV、法线、颜色等)传递给片元阶段
#endregion
#region 片元
//一般指光栅化阶段产生的、候选的像素点
//当三角形被投影到屏幕后,会覆盖一片像素区域
//每个像素位置对应一个片元,GPU 会为它准备一份数据(位置、UV、颜色等)
//作用:
//决定屏幕上每个像素的最终颜色
//着色器阶段:
//一般会在着色器中的 片元着色器 中进行处理和计算
//主要任务
//1.计算像素颜色(光照、材质、纹理采样)
//2.执行深度测试、混合、透明处理
//3.最终写入帧缓冲,形成屏幕像素
#endregion
//说人话
//顶点:就像建房子的"钢筋骨架"。
//片元:就是把框架之间的"砖块"一块块填上
//GPU渲染时:
//先有骨架(顶点)
//再填满砖块(片元)
//最后变成完整画面
#endregion
#region 知识点二 为什么顶点和片元会影响性能
//顶点:
//由于顶点数据需要进行计算
//因此以下因素会影响性能开销
//1.模型的顶点数越多,计算量越大
// 1-1.高顶点数模型,如未优化的高模、过密网格
// 1-2.复杂骨骼蒙皮,需要大量骨骼权重计算
//2.复杂的顶点着色器逻辑会放大开销
// 比如顶点动画(流体波动、噪声扰动、形变等等)
//片元:
//由于片元数据需要进行计算
//因此以下因素会影响性能开销
//1.分辨率和覆盖率
// 片元数直接与屏幕分辨率和绘制面积成正比
// 1-1.屏幕分辨率越高,片元数就越多,那么计算消耗就越大
// 1-2.全屏效果(后处理、屏幕空间特效)通常直接消耗片元性能
//2.过度绘制(Overdraw)
// 一个像素被多个物体反复覆盖计算
//3.高开销片元运算
// 复杂的片元着色器逻辑(多层纹理采样、分支、循环、PBR、阴影采样、SSR、体积雾、全屏后处理)
// 非常吃性能
#endregion
#region 知识点三 顶点和片元的优化思路
//顶点的主要优化思路就是
//从本质上减少顶点以及顶点相关的计算
//1.降低顶点数
// 1-1.LOD
// 1-2.网格简化
// 1-3.优化远距离对象(用Impostor(替身)技术)
// Billboard(广告牌)
// 多角度烘焙(在球面或半球面上采样多个角度,把结果打包到一张大纹理图集)
// Octahedral Impostor(八面体编码,把球面角度映射到 2D 纹理,通过一种高效编码方式存储多角度外观)
//2.蒙皮优化
// 减少骨骼数量、减少顶点权重、合并骨骼等
//3.顶点动画
// 把复杂的程序形变改为VAT(顶点动画纹理)
// 能贴图查表就别每帧算噪声
// VAT(顶点动画纹理):
// 把复杂的顶点动画(顶点位置/法线随时间变化)预先烘焙进贴图里
// 在运行时通过 Shader 从贴图中查表来驱动顶点
// 而不是实时在 CPU 或 GPU 上做骨骼/物理计算
//4.顶点着色器输出精简
// 减少 v2f 里插值数(TEXCOORD 通道),避免为片元传一堆用不到的数据
//5.顶点着色器精度和数学
// 移动端着色器中数值类型尽量用 half
// 避免大量 sin/cos/pow
// 能自己写计算过程,就别调用自带的一些高开销函数,比如:pow(x,2.0) → x*x
// 把复杂函数结果预计算在纹理里,运行时只采样
//6.合批处理
// 使用各批处理技术,减少DrawCall
//7.剔除先于变换
// 使用遮挡剔除、视锥剔除,减少要处理的内容
//等等
//片元的主要优化思路就是
//从本质上减少片元以及片元相关的计算
//1.降低分辨率
// 动态分辨率、注视点渲染等
//2.降低片元工作量
// 尽量减少纹理采样次数与层数(合并贴图通道、使用贴图图集)
// 片元着色器中减少循环/分支语法的使用
// 把复杂函数结果预计算在纹理里,运行时只采样
// 减少OverDraw
//3.减少全屏Pass
// 屏幕后处理中,能半分辨率就半分辨率
// 将多种屏幕后处理效果合并在一个Pass中处理
//4.避免 Early-Z (提前深度测试)失效
// 比如透明测试就会导致其失效
//5.Shader 分支收敛
// 尽量不要使用if/else语法,可以用一些函数替代
// 比如
// if (mask > 0.5) color = a; else color = b;
// 用插值函数替代
// color = lerp(b, a, step(0.5, mask))
//6.光照和阴影
// 降低光照和阴影质量,光照能用逐顶点就别用逐片元
//7.合理使用Mipmap功能
//等等
#endregion
#region 注意事项
//在开发时注意这些优化点
//可以减少性能问题的发生
//当发生性能问题时先定位问题再针对性解决问题
//结合性能分析窗口、帧调试窗口来分析定位问题,不要凭感觉
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com