首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >glTexImage2D + byte[]

glTexImage2D + byte[]
EN

Stack Overflow用户
提问于 2012-04-13 07:45:02
回答 3查看 2.1K关注 0票数 0

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

我使用的是glTexImage2D,我得到的只是一个白色的矩形,而不是像素化的纹理。第9个参数(指向像素数据的32位指针)是这个问题。我尝试了很多参数类型(byte,ref byte,byte[],ref byte[],int & IntPtr + byte[],out byte,out byte[],byte*)。glGetError()总是返回GL_NO_ERROR。一定是我做错了什么,因为它从来都不是一些乱七八糟的像素。它总是白色的。glGenTextures工作正常。与OpenGL中的always一样,第一个id的值为1。我可以毫无问题地画出彩色线条。所以我的纹理有问题。我控制着DllImport。因此,如果需要,我可以更改参数类型。

代码语言:javascript
复制
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);
代码语言:javascript
复制
[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);
EN

回答 3

Stack Overflow用户

发布于 2012-04-13 08:27:23

一个常见的错误是不更改最小滤镜,因为默认值是mipmapped,这会使纹理不完整。执行以下操作:

代码语言:javascript
复制
GL.glBindTexture(GL_TEXTURE_2D, id);
GL.glTexParameteri(GL_TEXTURE_2D, GL_MIN_FILTER, GL_NEAREST);

然后绘制纹理。

票数 3
EN

Stack Overflow用户

发布于 2012-04-13 15:57:26

尽管已上载某些内容,但纹理仍保持白色,这表示未正确上载所有mipmap级别,或过滤器设置未正确设置。

感兴趣的是

代码语言:javascript
复制
glTexParameteri(GL_TEXTURE_..., GL_MIN_FILTER, GL_...);

使用GL_NEAREST或GL_LINEAR禁用With映射。默认情况下会启用Mipmapping。

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

票数 1
EN

Stack Overflow用户

发布于 2012-04-14 04:15:41

您的P/Invoke声明错误。

简短的答案是:

代码语言:javascript
复制
[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内存不能移动。为此,您应该使用固定语句或其他垃圾收集器相关的方法。

例如:

代码语言:javascript
复制
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()时才移动它。

在固定语句中使用是另一种选择,但需要一个不安全的P/Invoke声明,并且在代码中使用它会有点冗长(对于每个调用,您必须定义一个不安全和固定的语句)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10133395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档