glTexImage2D + byte []

时间:2012-04-12 23:45:02

标签: c# opengl textures

如何将像素从简单字节数组上传到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中的值一样。我画没有任何问题的彩色线条。所以我的纹理有问题。我控制着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);

3 个答案:

答案 0 :(得分:3)

一个常见的错误是不更改MIN滤镜,因为默认是mipmapped,这会使纹理不完整。这样做:

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

然后绘制纹理。

答案 1 :(得分:1)

尽管上传了某些内容,但纹理仍为白色,这表示并非所有mipmap级别都已正确上传,或者过滤器设置未正确设置。

感兴趣的是

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

使用GL_NEAREST或GL_LINEAR禁用mipmapping。默认情况下启用Mipmapping。

另一个重要的事情是在上传之前设置数据的结构,即调用glTexImage。为此,您可以使用函数glPixelStorei来设置GL_UNPACK _...参数。您需要设置对齐,步幅等内容。我推荐你参考文档。

答案 2 :(得分: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:取 pixels 的地址,不要移动它,直到我在内存句柄上调用Free()。​​

使用fixed语句是另一种选择,但需要一个不安全的P / Invoke声明,并且在代码中使用它会更加冗长(对于每次调用,你必须定义一个 unsafe 和< em>修复语句。)