我正在编写一个 Sprite /纹理图集功能的支持类,使用 C# 和 OpenTK。
到目前为止,大多数功能都运行良好(正交 View 上的简单 2D 图块)。
我的问题与调用 GDI+ Bitmap.MakeTransparent() 方法设置颜色 (Magenta/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 上使用上面的代码测试了一个小演示,并观察到这些结果:
这让我感到惊讶,因为我预料到(GDI+ 和 OpenGL 以及 OpenTK 绑定(bind))在不同的机器上的行为是一样的。
就我已经吸收了 GDI+ 和 OpenGL/OpenTK API 文档而言,我认为我的困惑与这两点有关:
更新:
我已将代码精简为 Github 上的一个小项目:
https://github.com/sglasby/OpenGL_Transparent_Sprite
另外,我偶然发现了一个有效的参数组合
(LockBits() 的 arg 3 是 Format32bppPArgb),
尽管尚不清楚它为什么起作用,但鉴于文档暗示需要另一种像素格式:
http://msdn.microsoft.com/en-us/library/8517ckds.aspx
(这表明在调用 MakeTransparent 后,位图将采用 Format32bppArgb 格式)。
最佳答案
虽然这是您问题的一个单独问题,但在大多数情况下,您实际上应该 use premultiplied-alpha ( Format32bppPArgb
)。如果这种格式工作正常,那么理解为什么 Format32bppArgb
不起作用主要是一种学术练习。
我在带有 Intel 2000HD 的 Win7 上运行您的示例项目并得到以下结果:
Format32bppPArgb
工作正常 Format32bppRgb
工作正常 Format32bppArgb
被打乱了 在进一步调查中,这似乎与 OpenGL 无关,而是与
Bitmap.LockBits
的工作方式有关。在调试器上检查每种方法的
data.Stride
值:Format32bppPArgb
的步幅为 128(位图宽度的 4 倍,正确) Format32bppRgb
的步幅为 128(位图宽度的 4 倍,正确) Format32bppArgb
的步幅为 512(位图宽度的 16 倍,?) MSDN 没有在这里找到有用的东西。在这一点上,我不知道为什么会发生这种情况。如果我设法发现任何东西,我会更新这个答案。
编辑:瞧,如果在解包数据时强制正确的步幅,输出看起来是正确的:
GL.PixelStore(PixelStoreParameter.UnpackRowLength, data.Width * 4); // 4x for 32bpp
关于c# - Sprite/Texture Atlas : GDI+ Bitmap. MakeTransparent for color-key with OpenTK,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12417946/