我正在为精灵/纹理图集功能编写一个支持类,使用C#和OpenTK。 到目前为止,大多数功能都正常工作(正交视图上的简单2D图块)。
我的问题与调用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);
我在不同的盒子上使用上面的代码测试了一个小型演示,并观察这些结果:
令我感到惊讶的是,正如我所预料的那样(GDI +和OpenGL以及OpenTK绑定)在不同的盒子上的行为相同。
如果我已经吸收了GDI +和OpenGL / OpenTK API文档,我认为我的困惑与这两点有关:
调用MakeTransparent()+ LockBits()+ GL.TexImage2D()的正确方法是什么,以便将指定的颜色呈现为透明?
当为子矩形而不是整个图像调用LockBits()时,为什么我会为某些像素格式参数组合看到奇怪的显示结果(好像“步幅”被错误计算)? / p>
更新: 我已将我的代码缩减为Github上的一个小项目: https://github.com/sglasby/OpenGL_Transparent_Sprite
另外,我偶然发现了一个有效的参数组合 (LockBits()的第3行是Format32bppPArgb), 虽然目前尚不清楚为什么它可行,但鉴于文档暗示需要另一个pixelformat: http://msdn.microsoft.com/en-us/library/8517ckds.aspx (表示在调用MakeTransparent之后位图将在Format32bppArgb中)。
答案 0 :(得分:0)
虽然这是您问题的另一个问题,但在大多数情况下,您应该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