openGL透明像素意外变成白色

3
我注意到我的openGL纹理渲染存在一个大问题:
假定透明像素被呈现为实心白色。根据StackOverflow上讨论的类似问题的大多数解决方案,我需要设置glBlend/正确的函数,但是我已经设置了必要的gl状态,并且可以确定纹理加载正确(就我所知)。我的纹理加载函数如下:
GLboolean GL_texture_load(Texture* texture_id, const char* const path, const GLboolean alpha, const GLint param_edge_x, const GLint param_edge_y)
{
    // load image
    SDL_Surface* img = nullptr; 
    if (!(img = IMG_Load(path))) {
        fprintf(stderr, "SDL_image could not be loaded %s, SDL_image Error: %s\n", 
               path, IMG_GetError());
        return GL_FALSE;
    }


    glBindTexture(GL_TEXTURE_2D, *texture_id);
    // image assignment
    GLuint format = (alpha) ? GL_RGBA : GL_RGB;
    glTexImage2D(GL_TEXTURE_2D, 0, format, img->w, img->h, 0, format, GL_UNSIGNED_BYTE, img->pixels);

    // wrapping behavior
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, param_edge_x);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, param_edge_y);
    // texture filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);
    // free the surface
    SDL_FreeSurface(img);

    return GL_TRUE;
}

我使用Adobe Photoshop导出“网页用”24位+透明度.png文件-- 72像素/英寸,6400 x 720。我不确定如何设置颜色模式(8、16、32),但这可能与问题有关。我也使用默认的sRGB颜色配置文件,但曾经考虑过删除颜色配置文件。这没有起到任何作用。

无论如何,从Photoshop导出的png文件在透明像素上显示为纯白色。

如果我在Gimp中创建图像,则具有正确的透明度。导入Adobe.psd或.png似乎不起作用,在任何情况下,我更喜欢使用Photoshop进行编辑。

是否有人遇到过这个问题?我想Photoshop必须添加一些奇怪的元数据,或者我没有使用正确的颜色模式--或两者兼而有之。 (我担心这超出了Stack Overflow的范围,但我的问题涉及图像编辑和编程。不管怎样,请告诉我这是否是正确的地方。)

编辑:

在Photoshop和Gimp中,我都创建了一个测试案例--顺时针8个像素(红色、绿色、透明、蓝色)。

tiny square

在 Photoshop 中,透明方块读作 1、1、1、0,并显示为白色。在Gimp中,透明方块为 0、0、0、0。
我还检查了我的片段着色器,看看透明度是否正常工作。随着时间的推移改变alpha确实会增加透明度,因此alpha并没有被完全忽略。由于某种原因,1、1、1、0被视为实心。 此外,使用 glClearColor 将背景颜色设置为黑色似乎可以防止 alpha 增加透明度。
我不知道如何解释其中的一些行为,但感觉有点奇怪。无论颜色如何,alpha 值为 0 应该是相同的,不是吗?
(请注意,我在彼此之上渲染了几个形状,但我已经尝试了仅渲染一个以进行测试。)
我能做的最好的就是发布更多的设置代码(省略了一些细节):
// 顶点数组和缓冲区设置
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
// I think that the blend function may be wrong (GL_ONE that is).
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

glDepthRange(0, 1);
glDepthFunc(GL_LEQUAL);

Texture tex0;
// same function as above, but generates one texture id for me
if (GL_texture_gen_and_load_1(&tex0, "./textures/sq2.png", GL_TRUE,  GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE) == GL_FALSE) {
    return EXIT_FAILURE;
}

glUseProgram(shader_2d);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex0);
glUniform1i(glGetUniformLocation(shader_2d, "tex0"), 0);

bool active = true;
while (active) {
       glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

       // uniforms, game logic, etc.

       glDrawElements(GL_TRIANGLES, tri_data.i_count, GL_UNSIGNED_INT,   (void*)0);
}

我已经看到了关闭投票,但是我能否至少得到反馈,以便提供什么信息/在哪里提问?我已经很长时间无法解决这个问题。 - synchronizer
左上角:红色,右上角:绿色,左下角:蓝色,右下角:黄色。 - synchronizer
尝试在Photoshop中创建类似的示例并打印数据数组是否有帮助?此外,我正在使用RGBA而不是RGBA8。在Photoshop中应该设置什么并不是很清楚。嗯。 - synchronizer
@Rabbid76,我发现了一些东西。请看我的编辑。 - synchronizer
1个回答

6
我不知道如何解释其中一些行为,但某些东西似乎有问题。无论颜色如何,alpha值为0应该是相同的,不是吗?如果您想获得alpha通道为0.0时独立于红、绿和蓝通道的相同结果,则必须更改混合函数。请参见 glBlendFunc。使用:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

这导致红、绿和蓝通道被alpha通道相乘。如果alpha通道为0.0,则结果RGB颜色为(0, 0, 0)。如果alpha通道为1.0,则RGB颜色通道保持不变。
更多信息请参见Alpha Compositing, OpenGL Blending and Premultiplied Alpha

那是正确的。我还需要从后向前渲染四边形层,但我知道这可能是必要的。谢谢你的帮助。现在我得弄清楚为什么我会遇到滞后问题 - 但那是另一个问题。 - synchronizer

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