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

时间:2012-01-11 08:12:35

标签: c++ c opengl rendering transparency

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模式也是透明的:

Example

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

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

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

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 个答案:

答案 0 :(得分: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测试。

答案 1 :(得分:3)

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

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

此外,这已在documentation中解释。

  

<强> GL_LUMINANCE

     

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

- 编辑 -

  

任何方法都能保持每像素8位并达到同样的效果?

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

答案 2 :(得分:3)

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_INTENSITY的{​​{1}}格式为GL_LUMINANCE。< / p>

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

(Y, Y, Y, Y)

为:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

<强>替代:

您也可以使用glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); ,然后将普通混合模式用于非预乘alpha:

GL_ALPHA

备选方案#2:

您可以继续使用glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); ,并更改混合模式。

GL_LUMINANCE

这样做的缺点是,如果不使用像glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); 这样的东西(不是MSVC附带的OpenGL标题的一部分,你就不能使用GLEW或类似的东西),你就无法对纹理着色:

glBlendColor

备选方案#3:

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

答案 3 :(得分:0)

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

相关问题