4

OpenTKでC#を使用して、スプライト/テクスチャアトラス機能のサポートクラスを作成しています。これまでのところ、ほとんどの機能は正常に機能しています(正投影ビューの単純な2Dタイル)。

私の問題は、GDI + Bitmap.MakeTransparent()メソッドを呼び出して、カラーキーとして使用する色(マゼンタ/ 0xFFFF00FF)を設定したときの予期しない表示結果に関連しています。

ビットマップ.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);

上記のコードを使用して別のボクセンで小さなデモをテストし、次の結果を観察しました。

  • Windows 7ボックス:マゼンタピクセルは透明として機能します(望ましい結果)
  • Windows XPボックス:黒でレンダリングされたマゼンタピクセル
  • Ubuntu Linuxボックス:マゼンタとしてレンダリングされたマゼンタピクセル

(GDI +とOpenGLおよびOpenTKバインディング)が異なるボックスで同じように動作すると予想したので、これは私を驚かせます。

GDI+とOpenGL/OpenTK APIのドキュメントを吸収した限り、私の戸惑いは次の2つの点に関係していると思います。

  • 指定された色が透明としてレンダリングされるように、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になることを示します)。

4

1 に答える 1

0

これはあなたの質問とは別の問題ですが、ほとんどの場合、実際にはpremultiplied-alphaFormat32bppPArgb)を使用する必要があります。この形式が正しく機能している場合、なぜ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
于 2014-03-18T16:50:24.717 に答える