【问题标题】:Sprite/Texture Atlas: GDI+ Bitmap.MakeTransparent for color-key with OpenTKSprite/Texture Atlas: GDI+ Bitmap.MakeTransparent for color-key with OpenTK
【发布时间】:2014-03-19 00:50:24
【问题描述】:

我正在为精灵/纹理图集功能编写一个支持类,使用 C# 和 OpenTK。 到目前为止,大多数功能都运行良好(正交视图上的简单 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 框:洋红色像素呈现为洋红色

这让我很吃惊,因为我预计(GDI+ 和 OpenGL 以及 OpenTK 绑定)在不同的盒子上会表现相同。

就我吸收了 GDI+ 和 OpenGL / OpenTK API 文档而言,我认为我的困惑与这两点有关:

  • 什么是调用MakeTransparent() + LockBits() + GL.TexImage2D()的正确方法,从而导致指定的颜色被渲染为透明?

  • 为什么在为子矩形而不是整个图像调用 LockBits() 时,对于某些像素格式参数组合,我会看到奇怪的显示结果(好像“步幅”计算错误)?

更新: 我已经将我的代码缩减为 Github 上的一个小项目: https://github.com/sglasby/OpenGL_Transparent_Sprite

另外,我偶然发现了一个有效的参数组合 (LockBits() 的参数 3 是 Format32bppPArgb), 虽然目前尚不清楚 为什么 它的工作原理,因为文档暗示需要另一种像素格式: http://msdn.microsoft.com/en-us/library/8517ckds.aspx (说明调用 MakeTransparent 后,位图为 Format32bppArgb)。

【问题讨论】:

  • 对我来说,Format32bppArgb 在 Win7/Intel 上给出了打乱的结果。 Format32bppRgbFormat32bppPArgb 似乎有效。正在调查。
  • 出现了一些有趣的东西:Format32bppArpb 没有MakeTransparentdata.Stride = 128;与MakeTransparentdata.Stride = 512Format32bppPArgb 总是有 data.Stride = 128。不知道为什么会这样,但它可能指向解决方案。

标签: c# opengl opentk


【解决方案1】:

虽然这与您的问题不同,但在大多数情况下,您实际上应该use premultiplied-alpha (Format32bppPArgb)。如果这种格式工作正常,那么理解为什么Format32bppArgb 不能工作主要是一项学术练习。

我在 Win7 上使用 Intel 2000HD 运行您的示例项目并得到以下结果:

  • 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多