openGL 透明像素意外变白

openGL Transparent pixels unexpectedly White

我注意到我的 openGL 纹理渲染中存在一个大问题:

假设透明像素呈现为纯白色。根据 Whosebug 上讨论的类似问题的大多数解决方案,我需要设置 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;
}

我使用 Adob​​e Photoshop 导出 "for the web" 24 位 + 透明度 .png 文件 -- 72 pixels/inch, 6400 x 720。我不确定如何设置颜色模式 (8, 16、32),但这可能与问题有关。我也使用默认的 sRGB 颜色配置文件,但我想一次性删除颜色配置文件。这没有做任何事情。 无论如何,从 Photoshop 导出的 png 在透明像素上显示为纯白色。

如果我在例如Gimp,我有正确的透明度。导入 Adob​​e .psd 或 .png 似乎不起作用,无论如何我更喜欢使用 Photoshop 进行编辑。

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

编辑:

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

在 Photoshop 中,透明正方形被读取为 1, 1, 1, 0 并显示为白色。 在 Gimp 中,透明方块是 0, 0, 0, 0.

我还检查了片段着色器以查看透明度是否有效。随着时间的推移改变 alpha 确实会增加透明度,因此不会完全忽略 alpha。出于某种原因,1、1、1、0 算作实数。 此外,使用 glClearColor 将背景颜色设置为黑色似乎可以防止 alpha 增加透明度。

我不知道如何解释其中的一些行为,但似乎有些不对劲。 0 alpha 应该与颜色无关,不是吗?

(请注意,我在彼此之上渲染了几个形状,但我尝试只渲染一个用于测试目的。)

我能做的最好的就是 post 更多我的设置代码(省略了一些位):

// 顶点数组和缓冲区设置

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);
}

I don't know how to explain some of these behaviors, but something seems off. 0 alpha should be the same regardless of color, shouldn't it?

如果您希望 0.0 的 alpha 通道获得相同的结果,独立于红色、绿色和蓝色通道,则必须更改混合函数。参见 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