2011-11-24 51 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建議的範圍優化),它仍然運行得太慢了。

謝謝大家,感謝您的意見。