一、最近在优化客户端性能的时候,看到了Early ZBuffer。在VSPS中间GPU会对进行Z-buffer预判机制,对无效像素进行剔除,ATI、NVIDIA都有自己的Z-buffer预判机制。其实Doom3的时候已经开始使用预填充ZBuffer了,因为Doom3的PS需要处理阴影、NormalMap、LightMap及其他贴图处理,PS指令非常多,所以无效像素的剔除对性能影响是很大的,越早将无效像素剔除,显卡便能获得更多的时间对有效像素进行渲染。
二、Early-Z技术介绍(这段摘自http://tech.sina.com.cn/h/2008-06-17/09302262913.shtml)
当代的GPU都会采用Z-buffer去记录哪些像素是可见,而哪些像素是被遮挡而不可见。一个3D Frame最终要转换成为2D图像才能表示在屏幕上面,来自GPU连续的顶点流(vertices)会构建这个frame,从这个顶点流获取相应的2D坐 标去生成多边形。多边形的连续产生会覆盖原来的区域,因而Z-buffer的信息就是告诉ROP,哪些像素是可见哪些是不可见的。提前进行的Early- Z对比可以节省大量资源,因为同一个区域被多个多边形覆盖的次数轻而易举地达到原来的四倍甚至更高。
目前甚少方法可以利用Z-buffer信息去挑选或者排出被遮挡像素的渲染,Z-Cull就是这样的一个方法。Z-comparision通常 会发生在ROP的后期。问题就产生,意味着pixel要通过完整的ROP管线才能被发现是否可见。一些复杂的包含数千步骤的shader程序,即使是被遮 挡的pixel也全部通过流水线,这显然浪费了GPU的性能。Early-Z移去不可见像素在它们进入流水线之前,这样显然会提高性能,NVIDIA认为 这个操作提升22%附近的性能。
三、具体实现:场景渲染两遍:
4.在第二遍渲染的时候,因为浮点的误差,会有ZFighting现象,所以应允许一定的误差。
5.Early ZBuffer不一定适用所有场景,比如有大量实体的室外场景,因为DrawZPass毕竟也要绘制所有的实体,如果调用太多DP,性能反而会有所下降。
不过最后绘制天空盒时候,大家会问如何避免被FarPlane裁剪,有一个技巧可以解决,在SkyShader的VS输出投影后的位置时,这样设置:
Out.position = mul(mvp, vertex).xyww。// 不是Out.position = mul(mvp, vertex);
这样天空盒投影后的总是映射到FarPlane,这样就完美了,哈哈。这个方法时我在ATI的《Depth In Depth》文档中看到的。UI也是,游戏里的UI区域如果预先写入ZBuffer,也可以避免大量的无效PS处理。