2013-09-22 39 views
13

在Java中進行2D遊戲開發時,大多數教程都會創建一個緩衝策略來渲染。這非常合理。 但是,人們似乎傾向於將實際圖形繪製到緩衝區的方法。Java緩衝策略圖形或整型數組

一些教程創建了一個緩衝圖像,然後創建一個整數數組來表示各個像素的顏色。

private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); 

Graphics g = bs.getDrawGraphics(); 
g.setColor(new Color(0x556B2F)); 
g.fillRect(0, 0, getWidth(), getHeight()); 
g.drawImage(image, 0, 0, getWidth(), getHeight(), null); 

然而,一些其他教程不創建緩衝圖像,繪圖的像素爲int陣列,而是使用BufferStrategy中的圖形部件直接繪製它們的圖像的緩衝器。

Graphics g = bs.getDrawGraphics(); 
g.setColor(new Color(0x556B2F)); 
g.fillRect(0, 0, getWidth(), getHeight()); 

g.drawImage(testImage.image, x*128, y*128, 128, 128, null); 

我只是想知道,爲什麼要創建整個int數組,然後繪製它。這需要在實現矩形,拉伸,透明度等方面做更多的工作。緩衝策略的圖形組件已經具有可以很容易地調用的方法。 使用int數組會有一些巨大的性能提升嗎?

我已經看了幾個小時,所有我見過的網站只是解釋他們在做什麼,而不是他們爲什麼選擇這樣做。

+1

我不是100%確定,但我會出現一些人認爲它更快地更新int /像素數組,然後使用圖形API。這可能是真實的,人們也可能不知道如何創建兼容的圖形對象。使用緩衝策略應該提供幾乎直接訪問硬件層(如果可用),所以我不明白爲什麼你需要明白爲什麼你需要使用一個int數組,我只是這樣,而我懶得那樣;) – MadProgrammer

+0

是的,我正在用這兩種方法進行測試。使用int數組,我可以在我的fps開始減少到120以下之前改變大約27648000像素。使用圖形對象,我可以渲染透明圖像,放大到幾千倍的縮放矩形,這幾乎與int數組相等。 使用圖形對象似乎更有用。 – Kabistarz

+0

前段時間,我做了一個比較簡單的例子,只用了一些JPanel和一些自定義繪畫作爲主要對象。然後我得到了4500個這些物體都朝不同的方向移動,包括主要物體的旋轉,因此它指向它的運動方向。不確定幀速率是多少,但是我以25fps的速度刷新了它,並且它的表現非常出色。我認爲在渲染管道中有很多優化,可以使用DirectX或OpenGL,但需要進行實驗;) – MadProgrammer

回答

5

讓我們清楚一件事:代碼片段做同樣的事情 - 繪製圖像。然而,片段並不完整 - 第二個片段沒有顯示'testImage.image'實際是什麼或者它是如何創建的。但是他們最終都調用Graphics.drawImage()和drawImage()的所有變體在Graphics或Graphics2D中繪製一個Image,很簡單。在第二種情況下,我們根本不知道它是否是一個BufferedImage,一個VolatileImage,甚至是一個Toolkit Image。

所以在這裏實際繪製的圖畫沒有區別!

這兩個片段之間只有一個區別 - 第一個獲得最終內部支持Image實例的整數數組的直接引用。這使得可以直接訪問像素數據,而不必通過(緩衝)Image API使用相對較慢的getRGB()和setRGB()方法。爲什麼這樣做不能在上下文中具體化,在這個問題中,數組是獲得的,但永遠不會在代碼片段中使用。因此,爲了給出下面的解釋存在的任何理由,我們必須假定有人想要直接讀取或編輯圖像的像素,很可能出於優化原因,給出(緩衝)圖像API的「緩慢」操縱數據。

而那些優化的原因可能是一個過早的優化,可能會適得其反。


首先,這段代碼只工作,因爲圖像的類型是INT_RGB,它會給圖像一個IntDataBuffer。如果它是另一種類型的圖像,例如3BYTE_BGR,則此代碼將因ClassCastException而失敗,因爲後備數據緩衝區不會是IntDataBuffer。當您隻手動創建圖像並強制執行特定類型時,這可能不是什麼大問題,但圖像往往會從外部工具創建的文件中加載。其次,直接訪問像素緩衝區還有另一個更大的缺點:當你這樣做時,Java2D將拒絕加速該圖像,因爲它無法知道你何時將其更改爲在其控制之外進行更改。爲了清楚起見,加速是在視頻內存中保留未改變的圖像的過程,而不是在每次繪製時從系統內存中複製它。這可能是一個巨大的性能改進(或者如果您打破它,則會有所損失),具體取決於您使用的圖像數量。

How can I create a hardware-accelerated image with Java2D?

(作爲該相關問題表明你:你應該使用GraphicsConfiguration.createCompatibleImage()來構造BufferedImage的實例)。

所以實質上:嘗試對所有東西都使用Java2D API,不要直接訪問緩衝區。這種場外資源提供了一個好主意,正是採用了API已經支持您在不必再低的水平:

所有的

http://www.pushing-pixels.org/2008/06/06/effective-java2d.html

5

首先,有很多歷史方面。早期的API是非常基本的,所以做任何不平凡的唯一方法就是實現所有需要的基元。

原始數據訪問有點過時,我們可以嘗試做一些「考古學」來找出使用這種方法的原因。我認爲有兩個主要原因:

1濾鏡效果

讓我們不要忘記濾鏡效果(各種模糊的,等等)是簡單的,非常爲任何遊戲開發商重要和廣泛的應用。

enter image description here

的simples方法來實現與Java 1這樣的效果是使用int陣列和過濾器定義爲一個矩陣。赫伯特·希,例如,曾經有很多這樣的演示:

public class Blur { 

    public void convolve() { 
     for (int y = 1; y < height - 1; y++) { 
      for (int x = 1; x < width - 1; x++) { 
       int rs = 0; 
       int gs = 0; 
       int bs = 0; 
       for (int k = -1; k <= 1; k++) { 
        for (int j = -1; j <= 1; j++) { 
         int rgb = imgpixels[(y + k) * width + x + j]; 
         int r = (rgb >> 16) & 0xff; 
         int g = (rgb >> 8) & 0xff; 
         int b = rgb & 0xff; 
         rs += r; 
         gs += g; 
         bs += b; 
        } 
       } 
       rs /= 9; 
       gs /= 9; 
       bs /= 9; 
       newimgpixels[y * width + x] = (0xff000000 
         | rs << 16 | gs << 8 | bs); 
      } 
     } 
    } 
} 

當然,你可以實現使用getRGB,但原始數據的訪問方式更加有效。後來,Graphics2D提供更好的抽象層:

公共接口BufferedImageOp中

此接口描述 對BufferedImage 對象執行的單輸入/單輸出操作。它由AffineTransformOp,ConvolveOp, ColorConvertOp,RescaleOp和LookupOp實現。這些對象可以通過 傳遞到BufferedImageFilter中,以在ImageProducer-ImageFilter-ImageConsumer範例中的BufferedImage上操作。

2.雙緩衝

另一個問題是有關閃爍和很慢圖紙。雙緩衝消除了醜陋的閃爍,突然它提供了一個簡單的方法來做濾波效果,因爲你已經有了緩衝區。

enter image description here

就像一個最終的結論:)

我會說你所描述的情況是很常見的任何發展中的技術。有兩種方法可以實現同樣的目標:

  • 使用傳統的方法,代碼比較多,等
  • 依靠新的抽象層,提供技術等

也有一些有用的擴展,簡化你的生活更多,所以沒有必要使用int[] :)

+0

謝謝,不需要那樣做。這很有趣。而且,看起來好像我有足夠的觀點;) –