为什么使用OpenGL绘制8位纹理时,绘制的是黑色像素而不是透明像素?

5

OpenGL设置:

glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_DEPTH_TEST );
glEnable( GL_TEXTURE_2D );
glEnable( GL_CULL_FACE );
glCullFace( GL_BACK );
glClearColor( 0.0, 1.0, 1.0, 1.0 );

初始化纹理:

// 16x16 X pattern
uint8_t buffer[ 16*16 ] =
{
    255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
    0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0,
    0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0,
    0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0,
    0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0,
    0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0,
    0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0,
    0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0,
    255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255,
};

GLuint texture_id;
glGenTextures( 1, &texture_id );
glBindTexture( GL_TEXTURE_2D, texture_id );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

纹理使用glBegin/glEnd绘制为四边形。每个顶点的颜色为白色,完全不透明: {r=255,g=255,b=255,a=255}。
以下是一个示例场景。照片和奶酪都从PNG图像加载。奶酪有透明的孔,可以显示它后面的照片和背景。我期望的X​​图案也应该是透明的:

Example

为什么四边形是黑色而不是透明的,我该如何修复代码以绘制我期望的内容?

这个问题可能类似,但到目前为止,我无法将简短的答案应用于我的当前问题。

更新:我认为我解决了它,感谢下面的答案。 我改变了...

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, 16, 16, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer );

glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer );

...这将得到所需的结果。

4个回答

6

@Dietrich Epp的回答几乎正确,只是您要查找的格式是GL_ALPHA:

glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);

接着,将混合函数设置为glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);或者glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);,具体取决于你的值是否经过预乘。最后,将纹理环境设置为GL_MODULATE。

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

现在你可以使用glColor来设置“X”的颜色。
另一种方法是不使用混合而使用alpha测试。

3
因为亮度是一种颜色,而透明度(alpha)不是一种颜色。
如果您想要透明度,请使用不同的格式-GL_LUMANANCE_ALPHA或类似格式,并在不同的通道中存储透明度。
此外,这已经在文档中解释过了。
GL_LUMINANCE
每个元素都是单个亮度值。 GL将其转换为浮点数,然后通过将亮度值三次复制为红色,绿色和蓝色,并附加1来组装成RGBA元素。然后将每个分量乘以有符号比例因子GL_c_SCALE,加上有符号偏移GL_c_BIAS,并将其限制在范围[0,1]内(请参见glPixelTransfer)。
- 编辑 -
任何保持每像素8位并实现相同效果的方法吗?
我认为你可以“告诉”OpenGL初始图像是索引颜色,然后设置适当的RGBA调色板(其中每个元素R == G == B == A == index)。有关详细信息,请参见glPixelTransferglPixelMap

感谢澄清。我使用GL_LUMINACE,因为链接的问题似乎是这样建议的。有没有办法保持每像素8位并实现相同的效果? - x-x
@DrTwox:我认为你可以“告诉”OpenGL初始图像是索引颜色,然后设置正确的RGBA调色板(其中对于每个元素R == G == B == A == index)。不过我自己没有做过这个。有关详细信息,请参见glPixelTransfer和glPixelMap。 - SigTerm

3

将生成一个没有alpha通道的灰度图像的GL_RGBA8变为GL_INTENSITY

glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, 16, 16, 0,
             GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer);

GL_RGBA8 格式是由 GL_LUMINANCE 创建的,它给出的像素形式为 (Y, Y, Y, 1),而使用 GL_LUMINANCEGL_INTENSITY 则会得到 (Y, Y, Y, Y) 的像素。

您还需要更改混合模式以假定预乘 alpha,例如更改:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

to:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

替代方案:

你也可以使用 GL_ALPHA,并使用普通的非预乘alpha混合模式:

glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0,
             GL_ALPHA, GL_UNSIGNED_BYTE, buffer);

备选方案 #2:

您可以继续使用 GL_LUMINANCE,并更改混合模式。

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);

这种方法的缺点是,如果不使用 glBlendColor(它不是随 MSVC 附带的 OpenGL 头文件的一部分,因此您需要使用 GLEW 或类似的工具),则无法对纹理进行着色:

glBlendColor(...);
glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);

备选方案 #3:

使用OpenGL 3,并修改片段着色器以按所需方式处理单通道纹理。


我尝试了那些建议,但是我得到的只是一个白色的盒子,而不是带有白色X的黑色盒子。 - x-x
GL_INTENSITY不支持作为纹理格式。这就是为什么它是白色的原因。 - datenwolf

0

八位图像不使用颜色,它们有一个颜色调色板。零表示该图像的颜色调色板中的索引0,其中将包含256种颜色。八位图像没有用于透明度的Alpha通道。您使用的PNG图像具有Alpha通道。这将是一个32位图像,其中有8位红色,8位绿色,8位蓝色(24位颜色)和8位Alpha。您正在混合两种格式。


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