使用stb_image加载PNG作为OpenGL纹理会导致颜色错误

30

我正在使用stb_image加载32位PNG文件(RGBA),并用它创建OpenGL纹理。对于24位PNG文件(没有alpha通道),它可以正常工作,但是当我使用32位PNG文件时,就会出现问题。

以下是纹理应该看起来的样子:

Texture

但是在使用OpenGL渲染时,它看起来像这样(黑色部分应该是透明的,启用混合后就会透明):

Wrong Texture

以下是我加载纹理的方式:

int w;
int h;
int comp;
unsigned char* image = stbi_load(filename.c_str(), &w, &h, &comp, STBI_rgb);

if(image == nullptr)
    throw(std::string("Failed to load texture"));

glGenTextures(1, &m_texture);

glBindTexture(GL_TEXTURE_2D, m_texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

if(comp == 3)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if(comp == 4)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

glBindTexture(GL_TEXTURE_2D, 0);

stbi_image_free(image);

这些是窗口参数(使用SDL)

SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);

发生了什么?


转换张量 - undefined
2个回答

47
您实际的错误在于使用了comp来确定您传递给glTexImage2DformatGL_RBA/GL_RGBA)参数。这是因为当您使用stbi_load加载图像时,comp返回的值将始终匹配源图像,而不匹配返回的图像数据。
更具体地说,您的错误在于使用了STBI_rgb,导致stbi_load返回3字节像素,但随后您用GL_RGBA加载了4字节像素的glTexImage2D,因为当您加载32位图像时,comp的值为4。
如果您使用了STBI_rgb,则必须在调用glTexImage2D时将格式设置为GL_RGB,如果您使用了STBI_rgb_alpha,则必须设置为GL_RGBA
其他读者的奖励:
如果您有类似的问题,上述方法仍然无法解决问题,那么您的图像数据可能没有按照OpenGL所期望的对齐方式排列行。在调用glTexImage2D之前,请尝试glPixelStorei(GL_UNPACK_ALIGNMENT, 1);。有关更多信息,请访问https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_layout

1
我已经多次使用stb_image时遇到了GL_UNPACK_ALIGNMENT的需要。 stb_image文档表明它不会尝试执行任何类型的对齐 - 当将未对齐的NPOT(非二次幂)纹理传递给OpengGL时,这一点显然是最为明显的。 POT纹理将自然对齐,而NPOT纹理则不会。 - Tim Kane

25

在stbi_load函数调用中将STBI_rgb更改为STBI_rgb_alpha即可解决问题。

可能最好不要在指定RGBA时使用RGB :D


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接