使用stb_image加载32位png并使用GL_UNSIGNED_INT_8_8_8_8作为glTexImage2D类型参数时显示的颜色不正确

时间:2013-08-05 19:44:49

标签: opengl png textures glteximage2d

我正在学习如何在OpenGL中进行纹理处理,并且对我得到的一些结果感到有些困惑。

我正在使用stb_image加载以下棋盘图片:

Black and white checkerboard image

当我保存png图像时,我明确选择将其保存为32位。这将使我相信每个组件(RGBA)将存储为8位,总共32位 - 无符号整数的大小。但是,使用以下代码:

unsigned char * texture_data = 
  stbi_load("resources/graphics-scene/tut/textures/checker.png", &w, &h, nullptr, 4);

// ...

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
  GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,  texture_data);

的产率:

Black and white checkerboard in engine

如果我改为使用GL_UNSIGNED_BYTE作为类型参数,我会得到正确的结果。

另外,只是帮助它,我也尝试了下面的图像:

Colored checkerboard image

产生

Colored checkerboard in engine

GL_UNSIGNED_BYTE也会在这种情况下给出正确的结果。

我不确定这是否是我误解glTexImage2D或stb_image的情况(它是否将加载的数据转换为8位?这对我来说似乎不太可能)。

编辑:我终于找到了一个相关的帖子(已经搜索了一些但没有运气)。然而答案(https://stackoverflow.com/a/4191875/2507444)让我感到困惑。如果是这种情况 - type参数指定每个组件的字节数 - 那么GL_UNSIGNED_BYTE_3_3_2和GL_UNSIGNED_INT_8_8_8_8之类的内容究竟是什么意思???

1 个答案:

答案 0 :(得分:3)

  

如果是这种情况 - type参数指定每个组件的字节数 - 那么GL_UNSIGNED_BYTE_3_3_2和GL_UNSIGNED_INT_8_8_8_8之类的内容究竟是什么意思???

两者都有,具体取决于实际类型。

如果pixel transfer type只是一种数据类型,则它指定数据大小每个组件。如果它中有数字,那么类型指定数据的大小每像素;这些数字指定数据类型中的各个组件大小。

GL_UNSIGNED_INT_8_8_8_8表示OpenGL会将每个像素解释为无符号整数。第一个组件是高8位,下一个组件是接下来的8位,依此类推。

然而 ,问题来自于STB-image 无符号整数的事实。每个像素按RGBA顺序写为4个单独的字节。基本上,它是这样做的:

GLubyte arr[4] = {red, green, blue, alpha};

现在,这可能声音就像是同一件事。但事实并非如此。原因与endian issues有关。

在C / C ++中执行此操作时:

GLuint foo = 0;
foo |= (red << 24);
foo |= (green << 16);
foo |= (blue << 8);
foo |= (alpha << 0);

OpenGL的数据类型要求GLuint为无符号整数,大小为32位。假设redgreenbluealpha都是GLubyte s(8位无符号整数),C / C ++表示这将是将red位打包到高8位字节,将green打包到下一位,依此类推。 C和C ++标准要求这样做。

然而,C和C ++标准要求它起作用:

GLubyte *ptr = (GLubyte*)&foo;
ptr[0] == ((foo >> 24) & 0xFF);

也就是说,foo指向的内存的第一个字节不会作为red组件。

在小端字节排序中,32位整数的低字节先存储 ,而不是最后存储。

当OpenGL看到GL_UNSIGNED_INT时,这意味着它将完全按照您的CPU 的方式解释这四个字节。因此,GL_UNSIGNED_INT_8_8_8_8将完全相同于foo。它看到的内存的第一个字节将在小端机器上解释为低字节,而不是高字节。

STB-image不输出GL_UNSIGNED_INT_8_8_8_8。它将每个像素视为一个4字节数组,如上面的arr。因此,您必须告诉OpenGL这是您的数据存储方式。所以你说每个组件都是一个字节。这是GL_UNSIGNED_BYTE的作用。