2012-09-14 46 views
4

我寫精靈/紋理地圖功能的輔助類,使用C#與OpenTK色鍵。 到目前爲止,大多數功能工作正常(正交視圖上的簡單2D瓦片)。雪碧/紋理圖集:GDI + Bitmap.MakeTransparent與OpenTK

當調用GDI + Bitmap.MakeTransparent()方法設置用作顏色鍵的顏色(品紅色/ 0xFFFF00FF)時,我的問題與意外顯示結果有關。

這似乎是我使用不正確的像素格式參數的bitmap.LockBits()和GL.TexImage2D()調用。我的代碼是基於實際工作的例子,但其中有一個共同點是,傳遞給LockBits()的矩形是用於整個圖像的。

這涉及到這個過程的調用是:

<!-- language: C# --> 
Bitmap bitmap = new Bitmap(filename); 
bitmap.MakeTransparent(Color.Magenta); 

GL.GenTextures(1, out texture_id); 
GL.BindTexture(TextureTarget.Texture2D, texture_id); 

// "rect" is initialized for one of: 
// - the dimensions of the entire image 
//  (0, 0, bitmap.width, bitmap.height) 
// - the dimensions for a sub-rectangle within the image (for one tile) 
//  (tile_x * tile_width, tile_y * tile_height, tile_width, tile_height) 
// I observe different behaviors for a sub-rectangle, 
// as compared to the entire image, when in combination with 
// the .MakeTransparent() call. 
// 
// This code is in a load_tile() method, and the plan was to make 
// multiple calls per image file, one per tile to extract as a GL texture. 
// Without transparency, that worked fine. 

Rectangle rect = new Rectangle(xx, yy, width, height); 
BitmapData data = bitmap.LockBits(rect, 
            ImageLockMode.ReadOnly, 
            System.Drawing.Imaging.PixelFormat.Format32bppRgb); 
// In the absence of calling bitmap.MakeTransparent(), 
// images loaded and displayed as expected with Format24bppRgb. 
// With MakeTransparent() and Format32bppRgb, the results seem to be OS-dependent. 
//  (At first I thought the "correct" combination to be found, 
//  but then found that the results were "right" only under Windows 7.) 

GL.TexImage2D(
     OpenTK.Graphics.OpenGL.TextureTarget.Texture2D, // texture_target, 
     0,            // level, 
     OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgba, // internal_format 
     data.Width, data.Height,       // width, height, 
     0,            // border, 
     OpenTK.Graphics.OpenGL.PixelFormat.Bgra,   // pixel_format 
     OpenTK.Graphics.OpenGL.PixelType.UnsignedByte, // pixel_type 
     data.Scan0          // pixels 
     ); 
// Certainly the internal_format and pixel_format arguments are pertinent, 
// but other combinations I have tried produced various undesired display results. 
// After reading various (OpenGL, OpenTK, and GDI+) docs, still I am not enlightened.. 

bitmap.UnlockBits(data); 

我已經使用上面的代碼在不同的Boxen有測試了一個小的演示,並觀察這些結果:

  • 的Windows 7盒:品紅像素顯示爲透明(所需的結果)
  • Windows XP框:洋紅色像素呈現爲黑色
  • Ubuntu Linux框:呈現爲洋紅色的洋紅色像素a

這讓我很驚訝,因爲我預料到(GDI +和OpenGL以及OpenTK綁定)會在不同的框中發揮相同的作用。

要我吸收了GDI +和OpenGL/OpenTK API文檔的程度,我覺得我的困惑關於這兩點:

  • 什麼是調用MakeTransparent()+ LockBits(的正確方法)+ GL.TexImage2D(),以便導致指定的顏色呈現爲透明?

  • 當LockBits()調用子矩形而不是整個圖像時,爲什麼我會看到某些像素格式參數組合出現奇怪的顯示結果(好像「步幅」是錯誤計算的)?

更新: 我已經削弱了我的代碼放到Github上的一個小項目: https://github.com/sglasby/OpenGL_Transparent_Sprite

而且,我偶然發現了一個參數組合的作品 (LockBits的ARG 3()是Format32bppPArgb) , 雖然目前尚不清楚爲什麼工作,因爲文件暗示另一像素格式是想: http://msdn.microsoft.com/en-us/library/8517ckds.aspx (其中指出,位圖將在Format32bppArgb調用MakeTranspar後ENT)。

+0

對我來說,'Format32bppArgb'給出炒上的Win7 /英特爾的結果。 'Format32bppRgb'和'Format32bppPArgb'似乎工作。調查。 –

+0

一些有趣的事情顯示出來:沒有'MakeTransparent'的'Format32bppArpb'具有'data.Stride = 128'; 'MakeTransparent','data.Stride = 512'。 'Format32bppPArgb'總是有'data.Stride = 128'。不知道這是爲什麼,但它可能指向一個解決方案。 –

回答

0

雖然這是一個單獨的問題你的問題,在大多數情況下,你實際上應該use premultiplied-alphaFormat32bppPArgb)。如果這種格式工作正常,那麼理解爲什麼Format32bppArgb不起作用主要是一項學術活動。

我跑了英特爾2000HD在Win7的實例項目,並得到了以下結果:正確

  • Format32bppRgb工作正常
  • Format32bppArgb是經過加密的
  • 關於進一步

    • Format32bppPArgb作品調查,這似乎並沒有與OpenGL掛鉤,而是以Bitmap.LockBits的方式工作。

      檢查的data.Stride上的調試器對每一種方法的值:

      • Format32bppPArgb具有128步幅(4倍的位圖寬度,正確的)
      • Format32bppRgb具有128步幅(4倍的位圖寬度,正確的)
      • Format32bppArgb具有512一大步(16X位圖的寬度,?)

      MSDN不露面的東西ü這裏很有幫助。在這一點上,我不知道爲什麼會發生這種情況。我會更新這個答案,如果我設法發現任何東西。

      編輯:你瞧,如果你拆包數據時強制正確的步幅,輸出看起來是正確的:

      GL.PixelStore(PixelStoreParameter.UnpackRowLength, data.Width * 4); // 4x for 32bpp