1.顶点与片元简介
2.为什么顶点与片元会影响性能
3.顶点和片元的优化思路
1.顶点与片元简介
csharp
复制代码
1).顶点
表示模型的几何数据, 是组成三角形网格的点; 一个3D模型实际上就是由很多三角形拼接而
成的, 而三角形的角就是顶点
a.作用
是网格的框架点, 决定了模型的形状
b.着色器的顶点着色器对顶点进行处理和计算, 将模型的空间的顶点转换到裁剪空间, 屏幕空间
csharp
复制代码
2).片元
表示光栅化阶段产生的, 候选的像素点; 当三角形被投影到屏幕后, 会覆盖一片像素区域, 每个
像素位置对应一个片元, GPU会为它准备一份数据(位置, UV, 颜色等)
a.作用
决定屏幕上每个像素的最终颜色
b.着色器的片元着色器对片元进行处理和计算
- 计算像素颜色(光照, 材质, 纹理采样)
- 执行深度测试, 混合
- 最终写入帧缓冲, 形成屏幕像素
2.为什么顶点与片元会影响性能
csharp
复制代码
顶点数据需要进行计算, 以下因素会影响性能开销
a.模型的顶点数越多, 计算量越大
- 高顶点数模型, 如未优化的高模, 过密网格
- 复杂骨骼蒙皮, 需要大量骨骼权重计算
b.复杂的顶点着色器会放大开销, 比如流体波动, 噪声扰动等
csharp
复制代码
片元数据需要进行计算, 以下因素会影响性能开销
a.分辨率和覆盖率
- 屏幕分辨率越高, 片元数越多, 那么计算消耗就越大
- 全屏特效(后处理, 屏幕空间特效)通常直接消耗片元性能
b.过度绘制(OverDraw)
一个像素被多个物体反复覆盖计算
c.高开销片元运算
复杂的片元着色器逻辑(多层纹理采样, 分支, 循环, 全凭后处理等)
3.顶点和片元的优化思路
csharp
复制代码
1).顶点的主要优化思路
a.降低顶点数, 比如: LOD, 网格简化
b.蒙皮优化, 减少骨骼数量、减少顶点权重、合并骨骼等
c.顶点动画, 把复杂的程序形变改为VAT(顶点动画纹理), 能贴图查表就别每帧算噪声
d.顶点着色器输出精简, 减少v2f里插值数(TEXCOORD通道), 避免为片元传一堆用不到的数据
e.顶点着色器精度和数学, 移动端着色器中数值类型尽量用half, 避免大量 sin/cos/pow
能自己写计算过程,就别调用自带的一些高开销函数,比如:pow(x,2.0) → x*x
f.剔除先于变化, 使用遮挡剔除、视锥剔除,减少要处理的内容
csharp
复制代码
2).片元的主要优化思路就是: 从本质上减少片元以及片元相关的计算
a.降低分辨率, 动态分辨率
b.降低片元工作量
- 尽量减少纹理采样次数与层数(合并贴图通道、使用贴图图集)
- 片元着色器中减少循环/分支语法的使用
- 把复杂函数结果预计算在纹理里,运行时只采样
- 减少OverDraw
c.减少全屏Pass, 屏幕后处理中, 能半分辨率就半分辨率, 将多种屏幕后处理效果合并在一个
Pass中处理
d.光照和阴影, 降低光照和阴影质量, 光照能用逐顶点就别用逐片元
e.合理使用Mipmap功能
f.Shader 分支收敛, 尽量不要使用if/else语法, 可以用一些函数替代
比如: if (mask > 0.5) color = a; else color = b; 用插值函数替代
color = lerp(b, a, step(0.5, mask))
csharp
复制代码
Shader(顶点着色器/片元着色器)运行在GPU的SIMT(单指令多线程)架构上, 核心特点是:
GPU会把线程打包成"线程束(Warp, 通常32/64个线程为一组)", 同一个线程束内的所有线程必
须同步执行完全相同的指令(比如同时执行"采样纹理", 同时执行"计算颜色")
csharp
复制代码
当Shader中出现if/else时, 若线程束内的线程因条件不同, 比如部分像素满足if、部分满足
else, GPU无法同时执行两个分支, 只能:
- 先让所有线程执行if分支, 不满足条件的线程"空等"(暂停执行, 不产生有效结果)
- 再让所有线程执行else分支, 满足if条件的线程"空等"
- 最后合并两个分支的有效结果
这个过程中, 线程束内的线程被串行化, 空等的线程完全浪费算力, 相当于GPU的并行能力被大
幅削弱, 执行效率暴跌(极端情况下性能下降50%以上)