繁体   English   中英

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

[英]Why is drawing an 8bit texture with OpenGL drawing black pixels instead of transparent?

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将纹理绘制为四边形。 每个顶点的颜色为白色,带有完整的alpha:{r = 255,g = 255,b = 255,a = 255}。

这是一个示例场景。 照片和奶酪都是从PNG图像加载的。 奶酪有透明的孔,可以显示它背后的照片和背景。 我希望X模式也是透明的:

例

为什么四边形黑色而不是透明,任何我如何修复我的代码来绘制我期待的东西?

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

更新:我想我已经解决了,感谢下面的答案。 我变了...

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

......给出了期望的结果。

@Dietrich Epp的答案几乎是正确的,只是你要找的格式是GL_ALPHA:

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

然后将blend函数设置为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测试。

因为亮度是颜色,透明度(alpha)不是颜色。

如果您想要透明度,请使用不同的格式 - GL_LUMANANCE_ALPHA或类似的东西,并在不同的渠道中存储透明度。

此外,这已在文档中解释。

GL_LUMINANCE

每个元素是单个亮度值。 GL将其转换为浮点,然后通过将亮度值复制三次(红色,绿色和蓝色) 并将1附加为alpha来将其组合成RGBA元素。 然后将每个分量乘以带符号的比例因子GL_c_SCALE,加到有符号偏差GL_c_BIAS,并钳位到范围[0,1](参见glPixelTransfer)。

- 编辑 -

有什么方法可以保持每像素8位并达到同样的效果?

我认为你可以“告诉”OpenGL初始图像是索引颜色然后设置适当的RGBA调色板(其中每个元素R == G == B == A == index)。 有关详细信息,请参阅glPixelTransferglPixelMap

GL_RGBA8 (生成没有Alpha通道的灰度图像)更改为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_INTENSITYGL_LUMINANCE给出(Y, Y, Y, Y)

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

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

至:

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,并更改片段着色器以按所需方式处理单通道纹理。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM