Sprite/Texture Atlas:GDI + Bitmap.MakeTransparent,用于带有OpenTK的颜色键 [英] Sprite/Texture Atlas: GDI+ Bitmap.MakeTransparent for color-key with OpenTK

查看:55
本文介绍了Sprite/Texture Atlas:GDI + Bitmap.MakeTransparent,用于带有OpenTK的颜色键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用C#和OpenTK编写一个sprite/texture地图集功能的支持类. 到目前为止,大多数功能都可以正常工作(正交视图上的简单2D切片).

I am writing a support class for sprite/texture atlas functionality, using C# with OpenTK. Most functionality is working fine thus far (simple 2D tiles on an orthographic view).

我的问题与调用GDI + Bitmap.MakeTransparent()方法来设置用作色键的颜色(洋红色/0xFFFF00FF)时出现意外的显示结果有关.

My problem relates to unexpected display results when calling the GDI+ Bitmap.MakeTransparent() method to set a color (Magenta / 0xFFFF00FF) for use as a color-key.

似乎我对bitmap.LockBits()和GL.TexImage2D()调用使用了错误的像素格式参数.我的代码基于确实有效的示例,但是它们的共同点是传递给LockBits()的矩形适用于整个图像.

It would seem that I am using incorrect pixel format parameters for the bitmap.LockBits() and GL.TexImage2D() calls. My code was based on examples which indeed worked, but which had in common that the rectangle passed to LockBits() was for the entire image.

与此过程有关的呼叫是:

The calls which pertain to this process are:

<!-- 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上使用上面的代码测试了一个小型演示,并观察了以下结果:

I have tested a small demo using the code above on different boxen, and observe these results:

  • Windows 7框:洋红色像素起到透明作用(期望的结果)
  • Windows XP框:洋红色像素呈现为黑色
  • Ubuntu Linux框:洋红色像素呈现为洋红色

这让我感到惊讶,因为我预料到(GDI +和OpenGL以及OpenTK绑定)在不同的盒子上会起到相同的作用.

This surprises me, as I anticipated that (GDI+ and OpenGL and the OpenTK bindings) would act the same on different boxes.

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

To the extent that I have absorbed the GDI+ and OpenGL / OpenTK API documentation, I think my puzzlement relates to these two points:

  • 调用MakeTransparent()+ LockBits()+ GL.TexImage2D()以便导致将指定的颜色呈现为透明的正确方法是什么?

  • What is a correct way of calling MakeTransparent() + LockBits() + GL.TexImage2D(), so as to result in the specified color being rendered as transparent?

为什么当调用LockBits()而不是整个图像的子矩形时,对于某些像素格式参数组合,为什么看到奇怪的显示结果(好像步幅"被错误地计算了?) /p>

Why do I see strange display results (as if the "stride" was mis-calculated) for certain pixel format parameter combinations, when LockBits() is called for a sub-rectangle rather than the entire image?

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

Update: I have whittled down my code into a small project on Github: https://github.com/sglasby/OpenGL_Transparent_Sprite

此外,我偶然发现了一个有效的参数组合 (LockBits()的参数3为Format32bppPArgb), 尽管尚不清楚为什么起作用,但鉴于该文档暗示需要使用另一个pixelformat: http://msdn.microsoft.com/en-us/library/8517ckds.aspx (声明调用MakeTransparent后,位图将位于Format32bppArgb中.)

Also, I stumbled upon a parameter combination that works (arg 3 of LockBits() is Format32bppPArgb), though it is not clear why it works, given that the documentation implies another pixelformat is wanted: http://msdn.microsoft.com/en-us/library/8517ckds.aspx (which states that the bitmap will be in Format32bppArgb after calling MakeTransparent).

推荐答案

虽然这是您问题的单独问题,但在大多数情况下,您实际上应该

While this is a separate issue to your question, in most cases you should actually use premultiplied-alpha (Format32bppPArgb). If this format is working correctly, then understanding why Format32bppArgb does not work is mostly an academic exercise.

我在带有Intel 2000HD的Win7上运行了您的示例项目,并得到以下结果:

I ran your example project on Win7 with an Intel 2000HD and got the following results:

  • Format32bppPArgb正常工作
  • Format32bppRgb正常工作
  • Format32bppArgb被加扰
  • Format32bppPArgb works correctly
  • Format32bppRgb works correctly
  • Format32bppArgb is scrambled

在进一步研究中,这似乎与OpenGL无关,而是与Bitmap.LockBits的工作方式有关.

On further investigation, this does not appear to be linked to OpenGL, but rather to the way Bitmap.LockBits works.

针对每种方法,在调试器上检查data.Stride的值:

Check the values of data.Stride on the debugger for each approach:

  • Format32bppPArgb的步幅为128(正确为位图宽度的4倍)
  • Format32bppRgb的步幅为128(是位图宽度的4倍,正确)
  • Format32bppArgb的步幅为512(是位图宽度的16倍,?)
  • Format32bppPArgb has a stride of 128 (4x the bitmap width, correct)
  • Format32bppRgb has a stride of 128 (4x the bitmap width, correct)
  • Format32bppArgb has a stride of 512 (16x the bitmap width, ?)

MSDN在这里没有提供有用的信息.在这一点上,我不知道为什么会这样.如果我能发现任何内容,我将更新此答案.

MSDN does not turn up something useful here. At this point, I cannot tell why this is happening. I'll update this answer if I manage to uncover anything.

瞧,如果在拆包数据时强行执行正确的步幅,输出看起来是正确的:

lo and behold, if you force the correct stride when unpacking the data, the output looks correct:

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

这篇关于Sprite/Texture Atlas:GDI + Bitmap.MakeTransparent,用于带有OpenTK的颜色键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆