跳到主要內容

發表文章

目前顯示的是有「Graphics」標籤的文章

最佳化繪圖管線批次繪製物件(Batch Sprite)

最開始的時候,good的繪圖管線為了簡化設計和實作,物件在繪製時是一個一個畫。每個物件都是以一個 glDrawArray 畫出來,也就是說花費一個draw call畫出來。 一開始針對繪圖最佳化的規劃除了 貼圖合併 之外,另一個主要的功能是批次繪製功能作最佳化。現在終於實作了這個功能,可以大幅減少draw calls。 原來繪製物件的方式是透過glVertexPointer傳入長寬各為1的單位矩形,再使用 glDrawArray 畫出物件。底下是簡單的記錄,一步步將原本的繪製物件的管線轉換為批次繪圖方式。 1,第一步就是先把glTranslate、glScale及glRotate等方法替換掉。首先弄個可以計算4*4矩陣的工具,把這些方法都透過矩陣運算,得到一個轉換矩陣。再使用glLoadMatrix載入這個自行計算得到的轉換矩陣,然後看看是不是結果和原來一樣,如果和原來的結果是一樣的話,表示這個轉換矩陣的計算是正確的。 使用glLoadMatrix載入轉換矩陣時,如果結果不對,可以試試對轉換矩陣作一次transpose轉換,看是不是因為使用的矩陣定義和OpenGL相反。 2,第二步要利用上面求出且驗證正確的轉換矩陣,來再進一步替換掉glLoadMatrix。也就是將傳入glVertexPointer的矩形的4個點,用轉換矩陣轉換成最終結果的座標,並且不需要使用glLoadMatrix將轉換矩陣傳遞給OpenGL,因為我們已經自己作了座標的轉換。再來驗證看看結果是否正確,沒有問的話就可以進入到下一步。 3,以上兩個步驟已經將OpendGL轉換矩陣的部份都替換掉,由我們自已的底層計算得到。將來再作進一步最佳化時,還可以把這個預先計算得到的轉換矩陣cache起來,只在狀態變動及需要時再重新計算,如此還可以進一步提高繪圖速度。 接下來就是要將每一個繪製物件的動作儘可能的合併起來批次處理。基本原則是準備大一點的buffer,針對vertex、texture coord及color,分別使用glVertextPointer、glTexCoordPointer及glColorPointer餵給OpendGL,在最後使用 glDrawArray 繪出時再指定實際繪出的數量即可,這樣就能夠大符減少draw call。 使用 glDrawArray 批次...

Image Decoder and Render Pipe Improvement

作了幾個更新。 1,圖形解碼(Image Decoder) 原本Good使用來解碼圖形的程式庫是 ImageStone ,這是個C++的影像處理程式庫。當初會用它,是因為容易使用。但因為只是用來載入圖形,所以在作 PSP版移植 時,就另外作了一個簡單的image decoder,不過當時只作了 PNG 格式的支援就沒再繼續進行。 現在繼續完成了 BMP 及 JPEG 格式的支援。 BMP:BMP的格式比較簡單些,是自行實作。 PNG :使用 libpng 。 JEPG:使用 libjpeg 。 目前還缺 GIF 的支援,另外取消 TGA 格式支援。 而在Windows平台上,則直接使用系統提供的 GDI+ 來作圖形解碼。將ImageStone替換掉後,code size縮減了約40k。 2,繪圖模組(Render Pipe) 基於前次的 rect packing 的研究結果,利用昨天台風假在家,花了幾個小時將演算法整合進到GoodEngine的繪圖模組裡,過程相當順利。 以範例遊戲 25940m 為例,遊戲全部使用了9張貼圖。以原本的繪圖引擎來說,這9張貼圖會被載入並建立成各自獨主的9張貼圖。如此在繪圖時,貼圖間的切換就會相當頻繁。現在加上texture packing支援後,9張貼圖可以全部合併到1張1024x1024的貼圖內,這樣就能省掉切換的時間提升速度,同時也省掉額外貼圖記憶體的浪費。 3,新增範例 新增了一個簡單的範例solar,建立簡單的太陽系系統示範物件階層架構的使用。 這個範例建立三個貼圖物件用來代表太陽、地球及月球。月球繞行parent object地球轉,地球繞行parent object太陽旋轉,而太陽慢慢自轉。

PNG秀圖的處理

首先看看底下這張PNG格式圖檔,正確顯示結果應該如下原圖所示。 載入後以API AlphaBlend 作Per-Pixel Alpha Blend如下所示,結果是不正確。 檢查AlphaBlend規格發現,以AlphaBlend作Per-Pixel Alpha Blend時,會以底下公式計算每一個像素的值。 Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red; Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green; Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue; 要作正確PNG秀圖(或者說有帶Alpha Channel的圖),底下列出虛擬碼。 if (255 == Src.Alpha) { Dst.Red = Src.Red; Dst.Green = Src.Green; Dst.Blue = Src.Blue; } else if (0 != Src.Alpha) { Dst.Red = Src.Red * Src.Alpha + (1 - Src.Alpha) * Dst.Red; Dst.Green = Src.Green * Src.Alpha + (1 - Src.Alpha) * Dst.Green; Dst.Blue = Src.Blue * Src.Alpha + (1 - Src.Alpha) * Dst.Blue; } ; AlphaBlend測試代碼: BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; // 目前僅支援此操作. bf.BlendFlags = 0; // 必須為0 bf.SourceConstantAlpha = 255; // 使用Per-Pixel Alpha bf.AlphaFormat = AC_SRC_ALPHA; // 使用Per-Pixel Alpha dc.AlphaBlend(0, 0, sz.cx, sz.cy, memdc, 0, 0, sz.cx, sz.cy, bf);