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