【问题标题】:Why is drawing an 8bit texture with OpenGL drawing black pixels instead of transparent?为什么用 OpenGL 绘制 8 位纹理会绘制黑色像素而不是透明像素?
【发布时间】:2012-02-07 14:54:22
【问题描述】:

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 图案也是透明的:

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

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

...它给出了想要的结果。

【问题讨论】:

    标签: c++ c opengl rendering transparency


    【解决方案1】:

    @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 测试。

    【讨论】:

      【解决方案2】:

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

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

      另外,这已经在documentation 中进行了解释。

      GL_LUMINANCE

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

      --编辑--

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

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

      【讨论】:

      • 感谢您的澄清。我使用了 GL_LUMINACE,因为这就是链接问题所暗示的。有什么办法可以保持每像素8bit并达到同样的效果?
      • @DrTwox:嗯,我认为你可以“告诉”OpenGL 初始图像是索引颜色,然后设置适当的 RGBA 调色板(其中每个元素 R==G==B==A ==索引)。不过,我自己并没有这样做。有关详细信息,请参阅 glPixelTransfer 和 glPixelMap。
      【解决方案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_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,并更改片段着色器以按所需方式处理单通道纹理。

      【讨论】:

      • 我尝试了这些建议;而不是一个带有白色 X 的黑盒子,我只得到一个白盒子。
      • GL_INTENSITY 不支持作为纹理格式。这就是为什么它是白色的。
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-25
        • 1970-01-01
        相关资源
        最近更新 更多