2012-04-12 74 views
0

如何将像素从简单的字节数组上传到OpenGl纹理?glTexImage2D + byte []

我使用的是glTexImage2D,我得到的只是一个白色矩形而不是像素化纹理。第9个参数(像素数据的32位指针)是IMO的问题。我尝试了很多参数类型(byte,ref byte,byte [],ref byte [],int & IntPtr + Marshall,out byte,out byte [],byte *)。 glGetError()总是返回GL_NO_ERROR。必须有我做错的事情,因为它从来不是一些乱码像素。它总是白色的。 glGenTextures的作品正确。像OpenGL一样,第一个id的值为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); 
+0

这是什么让你觉得这是图像上传这就是问题所在? – 2012-04-12 23:57:52

+0

另外,你如何编组一个.NET字节数组到C API函数?您的评论“我在控制DllImport”暗示您没有使用OpenTK或其他预先制作的OpenGL绑定。那么代码是什么样的? – 2012-04-13 00:10:24

+0

那会是什么呢?我用GL_QUADS绘制它,但它总是用我当前的glColor()(白色)填充。我绑定了纹理ID并启用了GL_TEXTURE_2D。 – miniMe 2012-04-13 00:13:22

回答

3

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

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

然后绘制纹理。

+0

好的thx Matias,现在我看到了SOMETHING。现在我可以发送我的byte []像素并做一些可见的更改。我仍然有一些错误。也许我仍然需要以某种方式编组字节?我在那里发布了我的dllimport。 – miniMe 2012-04-13 04:33:06

1

尽管已经上传了纹理,但纹理仍为白色,表明不是所有mipmap级别都能正确上传,或者过滤器设置设置不正确。

感兴趣的是那么

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

随着GL_NEAREST或GL_LINEAR禁用mipmap处理。 Mipmapping默认启用。

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

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内存不能移动。为此,您应使用固定的语句或其他垃圾回收器相关的方法。

例如:

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函数的对象参数是指与数据的任何阵列中使用(那些实施阵列类的对象(即,字节[],简单的[],int []等等)。

本质上上面的代码告诉GC:取地址像素,并且不要移动它直到我调用内存句柄上的Free()。

页使用的固定语句是另一种选择,但需要一个不安全的P/Invoke声明,这是一个有点冗长的代码中使用它(每叫你必须定义一个不安全固定语句)。

+0

上面的问题可以通过添加行GL.glTexParameteri(GL_TEXTURE_2D,GL_MIN_FILTER,GL_NEAREST)来解决;有人知道为什么纹理会变白吗?它在我的项目中回到了白色,并且我设置了全部4 tex参数。 – miniMe 2012-04-16 21:57:28