四、光栅化与像素处理:从三角形到屏幕上的每一个像素
好,咱们进入第四章节。光栅化与像素处理,说白了就是GPU把三角形变成屏幕上可见像素的那一步。这一步如果没做好,前面顶点着色算得再快也是白搭。我个人习惯把这一阶段称为「填色流水线」,因为它决定了最终画面的质量和性能。
核心观点:光栅化阶段的效率,直接决定了你的游戏或应用能跑多快、画质能开多高。很多性能瓶颈其实都藏在这里。
4.1 光栅化效率影响因素
光栅化就是把三角形转换成像素片元的过程。影响效率的因素有哪些?我列几个关键点:
- 三角形尺寸:小三角形(比如小于2x2像素)会导致大量无效计算。我在项目中遇到过,一个场景里全是细碎的小三角形,光栅化效率直接腰斩。
- 三角形形状:瘦长三角形比等边三角形更难处理,因为边界遍历的步长不均匀。
- 屏幕分辨率:分辨率越高,需要处理的像素越多,这个不用多说。
- 多重采样(MSAA):每个像素要采样多个点,计算量成倍增加。
你想想看,如果一个三角形只覆盖了半个像素,GPU还是要为它做完整的边界计算。这就是浪费。我建议在建模阶段就控制好三角形密度,别让太多小三角形出现在远处。
4.2 Early-Z与Late-Z测试
这是GPU里一个非常巧妙的设计。Early-Z测试,就是在像素着色器执行之前,先做深度测试。如果这个像素被挡住了,直接扔掉,不用跑着色器了。
为什么会这样设计?因为像素着色器很贵啊!能省则省。
我的经验:Early-Z在渲染不透明物体时效果极好。但如果你用了alpha测试或discard操作,Early-Z就会失效,因为GPU不知道这个像素最终会不会被丢弃。这时候就会退回到Late-Z模式。
Late-Z测试是在像素着色器执行之后再做深度测试。说白了就是先算颜色,再判断要不要。这显然浪费了计算资源。所以,尽量让不透明物体先渲染,利用Early-Z把被遮挡的像素提前干掉。
| 特性 | Early-Z | Late-Z |
|---|---|---|
| 执行时机 | 像素着色器之前 | 像素着色器之后 |
| 性能影响 | 节省大量计算 | 浪费计算资源 |
| 适用场景 | 不透明物体 | 透明物体、alpha测试 |
| 是否支持discard | 不支持 | 支持 |
嗯,这里要注意:如果你在像素着色器里写了discard或者clip,Early-Z就会自动关闭。我曾经调试过一个性能问题,发现帧率突然掉了一半,查了半天才发现是某个材质用了alpha test。
4.3 像素着色器优化
像素着色器是GPU里最繁忙的单元,没有之一。优化它,收益最大。
我总结了几条实用原则:
- 减少指令数:能少算就少算。比如把光照计算从像素着色器移到顶点着色器,或者用预计算纹理代替实时计算。
- 避免分支:像素着色器里的if-else会导致SIMD效率下降。因为同一个warp里的像素必须走同一个分支。我建议用lerp或step函数代替分支。
- 减少纹理采样:纹理采样是像素着色器里最贵的操作之一。能合并就合并,能用低分辨率就用低分辨率。
- 使用half精度:很多计算不需要float32精度,用half能省带宽和计算单元。
避坑指南:我曾经把一个像素着色器从200条指令优化到50条,结果发现瓶颈在纹理带宽上。所以,先profile再优化,别凭感觉瞎改。
4.4 Overdraw问题与解决方法
Overdraw,说白了就是同一个像素被画了多次。比如一个透明玻璃杯,它后面的物体要先画,然后玻璃杯再画上去,这个像素就被画了两次。
Overdraw的危害很明显:浪费像素着色器计算、浪费带宽、降低帧率。
怎么解决?我常用的方法:
- 深度预渲染(Z-prepass):先只写深度,不写颜色。这样后面的渲染就能利用Early-Z把被遮挡的像素提前扔掉。代价是多跑一次顶点着色器,但像素着色器省下来的更多。
- 排序渲染:不透明物体从近到远渲染,透明物体从远到近渲染。这样Early-Z能发挥最大作用。
- 使用Hierarchical-Z:现代GPU都有层级深度缓冲,可以在更粗的粒度上提前剔除像素块。
- 减少透明物体:透明物体是Overdraw的重灾区。能用不透明就用不透明,或者用alpha-to-coverage代替alpha blend。
我记得有一次做移动端优化,场景里全是半透明的粒子特效,Overdraw达到了8x。后来改用深度预渲染+限制粒子数量,Overdraw降到了2x,帧率从20fps直接飙到60fps。
知识体系图
下面这张图展示了光栅化与像素处理的核心逻辑,我画了个流程图帮你理清思路:
这张图把整个流程串起来了。从光栅化开始,经过Early-Z筛选,再到像素着色器计算,最后经过Late-Z确认,写入帧缓冲。Overdraw和优化建议都在底部做了总结。
最后说一句:光栅化阶段的优化,很多时候不是靠改代码,而是靠调整渲染顺序和渲染策略。我见过太多人一上来就优化像素着色器,结果发现瓶颈在Overdraw上。先看profile数据,再动手,这是铁律。
公众号:蓝海资料掘金营,微信deep3321