0

単純なバイト配列から OpenGl テクスチャにピクセルをアップロードするにはどうすればよいですか?

私はglTexImage2Dを使用していますが、ピクセル化されたテクスチャではなく白い四角形しか得られません。9 番目のパラメーター (ピクセル データへの 32 ビット ポインター) は、IMO 問題です。そこで多くのパラメーターの型を試しました (byte、ref byte、byte[]、ref byte[]、int & IntPtr + Marshall、out byte、out byte[]、byte*)。glGetError() は常に GL_NO_ERROR を返します。ちんぷんかんぷんなピクセルではないので、何か間違っているに違いありません。いつも白です。glGenTextures は正しく動作します。最初の id の値は、OpenGL の場合と同様に 1 です。そして、問題なく色付きの線を描きます。そのため、テクスチャリングに何か問題があります。私は DllImport を管理しています。したがって、必要に応じてパラメーターの型を変更できます。

GL.glBindTexture(GL.GL_TEXTURE_2D, id);
int w = 4;
int h = 4;
byte[] bytes = new byte[w * h * 4];
for (int i = 0; i < bytes.Length; i++)
    bytes[i] = (byte)Utils.random(256);
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, w, h, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, bytes);


[DllImport(GL_LIBRARY)] public static extern void glTexImage2D(uint what, int level, int internalFormat, int width, int height, int border, int format,
            int type, byte[] bytes);
4

3 に答える 3

3

よくある間違いは、MIN フィルターを変更しないことです。これは、デフォルトがミップマップされているため、テクスチャが不完全になるためです。これを行う:

GL.glBindTexture(GL_TEXTURE_2D, id);
GL.glTexParameteri(GL_TEXTURE_2D, GL_MIN_FILTER, GL_NEAREST);

次にテクスチャを描きます。

于 2012-04-13T00:27:22.510 に答える
1

何かがアップロードされているにもかかわらずテクスチャが白いままである場合は、すべてのミップマップ レベルが適切にアップロードされていないか、フィルター設定が正しく設定されていないことを示しています。

興味深いのは

glTexParameteri(GL_TEXTURE_..., GL_MIN_FILTER, GL_...);

GL_NEAREST または GL_LINEAR を使用してミップマッピングを無効にします。ミップマッピングはデフォルトで有効になっています。

もう 1 つの重要なことは、アップロードする前にデータの構造を設定することです。つまり、glTexImage を呼び出します。このために、関数glPixelStoreiを使用して GL_UNPACK_... パラメータを設定します。アライメント、ストライドなどを設定する必要があります。ドキュメントを参照します。

于 2012-04-13T07:57:26.030 に答える
0

P/Invoke 宣言が間違っています。

簡単な答えは次のとおりです。

[System.Runtime.InteropServices.DllImport(Library, EntryPoint = "glTexImage2D", ExactSpelling = true)]
internal extern static void glTexImage2D(int target, int level, int internalformat, Int32 width, Int32 height, int border, int format, int type, IntPtr pixels);

この P/Invoke 宣言は安全なものです (直接ポインターを使用するのではなく、IntPtrを使用します)。

問題は .NET メモリ管理です。メモリ ブロックは特定のメモリ アドレスに固定されていません。ガベージ コレクタ (GC) はメモリをどこにでも自由に移動できます (たとえば、スタックに割り当てられたメモリをヒープ空間に移動したり、その逆に移動したりできます)。

実際、必要なのは、.NET GC にメモリを移動しないように指示することです。これを行うには、fixedステートメントまたはその他のガベージ コレクター関連のメソッドを使用する必要があります。

例えば:

public static void TexImage2D(int target, int level, int internalformat, Int32 width, Int32 height, int border, int format, int type, object pixels) {
    GCHandle pp_pixels = GCHandle.Alloc(pixels, GCHandleType.Pinned);
    try {
        if      (Delegates.pglTexImage2D != null)
            Delegates.pglTexImage2D(target, level, internalformat, width, height, border, format, type, pp_pixels.AddrOfPinnedObject());
        else
            throw new InvalidOperationException("binding point TexImage2D cannot be found");
     } finally {
         pp_pixels.Free();
     }         
}

TexImage2D関数の object パラメータは、任意のデータ配列 ( Arrayクラスを実装するオブジェクト(つまり、byte[]、short[]、int[] など) で使用することを意図しています。

基本的に、上記のコードは GC に指示します:ピクセルのアドレスを取得し、メモリ ハンドルで Free() を呼び出すまで移動しないでください。

fixed ステートメントを使用することも別のオプションですが、安全でない P/Invoke 宣言が必要であり、コードで使用すると少し冗長になります (呼び出しごとに、安全でない固定ステートメントを定義する必要があります)。

于 2012-04-13T20:15:40.703 に答える