我正在编写一个 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 上使用上面的代码测试了一个小演示,并观察到这些结果:
  • Windows 7 框:洋红色像素充当透明(所需结果)
  • Windows XP 框:洋红色像素呈现为黑色
  • Ubuntu Linux box:洋红色像素呈现为洋红色

  • 这让我感到惊讶,因为我预料到(GDI+ 和 OpenGL 以及 OpenTK 绑定(bind))在不同的机器上的行为是一样的。

    就我已经吸收了 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
    (这表明在调用 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/

    10-09 18:18