2011-11-24 31 views
3

我正在写一个3D图形库作为我的一个项目的一部分,而且我正处于一切正常工作的地步,但还不够好。关于优化Z缓冲区实现的建议?

特别是,我的主要头疼的是,我的像素填充率为可怕慢 - 绘制跨越一个800x600窗口的一半我的目标机器上的三角形时,我甚至不能管理30 FPS(这是无可否认的旧电脑,但它应该是能够管理这个

我跑gprof的在我的可执行文件,我结束了以下有趣的台词:。

% cumulative self    self  total   
time seconds seconds calls ms/call ms/call name  
43.51  9.50  9.50        vSwap 
34.86  17.11  7.61 179944  0.04  0.04 grInterpolateHLine 
13.99  20.17  3.06        grClearDepthBuffer 
<snip> 
0.76  21.78  0.17  624  0.27 12.46 grScanlineFill 

功能vSwap是我的双缓冲区交换功能,并且它也执行语音处理,所以对我来说测试程序将花费大量时间在那里等待。 grScanlineFill是我的三角形绘制功能,它创建一个边缘列表,然后调用grInterpolateHLine实际填充三角形。

我的引擎当前正在使用Z缓冲来执行隐藏表面去除。如果我们对(假设的)vsynch开销进行折扣,那么事实证明测试程序花费了其执行时间的85%,或者清除深度缓冲区,或者根据深度缓冲区中的值写入像素。我的深度缓冲区清除功能本身就很简单:将浮点数的最大值复制到每个元素中。功能grInterpolateHLine是:

void grInterpolateHLine(int x1, int x2, int y, float z, float zstep, int colour) { 
    for(; x1 <= x2; x1 ++, z += zstep) { 
     if(z < grDepthBuffer[x1 + y*VIDEO_WIDTH]) { 
      vSetPixel(x1, y, colour); 
      grDepthBuffer[x1 + y*VIDEO_WIDTH] = z; 
     } 
    } 
} 

我真的不知道怎样才能改善这种,特别是考虑到vSetPixel是一个宏。

我的优化思路整个股市已经削减到精确之一:

  1. 使用整数/定点深度缓冲。

,我有整数/定点深度缓冲的问题是,插值可以很烦人,我实际上并不定点数库呢。有任何进一步的想法吗?任何意见将不胜感激。

+0

使用像OpenGL这样的硬件解决方案? – Lalaland

+1

哈哈,不幸的是,这个项目的重点是要教自己如何真正起作用。类似于使用OpenGL等的对立面。 – Ethereal

+1

也gcc有一些固定点支持本身:http://gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html – Lalaland

回答

3

你应该看看Quake之类的源代码 - 考虑它在15年前在Pentium上可以实现的功能。其z缓冲区实现使用跨度而不是每像素(或片段)深度。否则,您可以查看Mesa中的光栅化代码。

1

很难真正知道在没有看到其他代码的情况下可以进行更高级的优化。虽然我有一些小小的观察。

在grInterpolateHLine中不需要多次计算x1 + y * VIDEO_WIDTH。即:

void grInterpolateHLine(int x1, int x2, int y, float z, float zstep, int colour) { 
    int offset = x1 + (y * VIDEO_WIDTH); 
    for(; x1 <= x2; x1 ++, z += zstep, offset++) { 
     if(z < grDepthBuffer[offset]) { 
      vSetPixel(x1, y, colour); 
      grDepthBuffer[offset] = z; 
     } 
    } 
} 

同样,我猜你vSetPixel做了类似的计算,所以你应该能够使用相同的偏移有作为,然后你只需要增加抵消,而不是X1在每个循环迭代。机会可以延伸回调用grInterpolateHLine的函数,然后您只需要每个三角形进行一次乘法运算。

您还可以使用深度缓冲区执行其他一些操作。大多数情况下,如果线的第一个像素失败或通过深度测试,则线的其余部分将具有相同的结果。因此,在第一次测试之后,您可以编写一个更高效的汇编块来一次测试整条线,如果通过,您可以使用更高效的块存储器设置程序来设置像素值和深度值,而不是在像素值和深度值处设置一个一次。如果线条仅部分遮挡,则只需测试/设置每个像素。

此外,不确定您的旧计算机是什么意思,但是如果您的目标计算机是多核,那么您可以将其拆分为多个核心。您也可以为缓冲区清除功能执行此操作。它可以帮助很多。

+0

我想过这个,但显然我的GCC版本足够智能,可以自动执行此优化。 (通过阅读反汇编确认)。我的这个项目的目标是一台Pentium III单核机器。 我一定会尝试你的线条优化。谢谢! – Ethereal

0

我最终通过用Painter算法替换Z缓冲区来解决这个问题。我使用SSE编写了一个Z-buffer实现,它创建了一个可以绘制像素的位掩码(加上Gerald建议的范围优化),它仍然运行得太慢了。

谢谢大家,感谢您的意见。