Opengl:使用单通道纹理作为alpha通道来显示文本

时间:2012-03-24 03:27:17

标签: c++ opengl text opengl-4

我要做的是从单个通道数据阵列将纹理加载到硬件中,并使用它的alpha通道将文本绘制到对象上。我正在使用opengl 4.

如果我尝试使用4通道RGBA纹理来完成此操作,它可以正常工作,但无论出于何种原因,当我尝试加载单个通道时,我只会得到一个乱码图像,我无法找出原因。 我通过将一系列字形的纹理位图数据与以下代码组合成一个纹理来创建纹理:

int texture_height = max_height * new_font->num_glyphs;
int texture_width = max_width;

new_texture->datasize = texture_width * texture_height;
unsigned char* full_texture = new unsigned char[new_texture->datasize];

// prefill texture as transparent
for (unsigned int j = 0; j < new_texture->datasize; j++)
    full_texture[j] = 0;

for (unsigned int i = 0; i < glyph_textures.size(); i++) {
    // set height offset for glyph
    new_font->glyphs[i].height_offset = max_height * i;
    for (unsigned int j = 0; j < new_font->glyphs[i].height; j++) {
        int full_disp = (new_font->glyphs[i].height_offset + j) * texture_width;
        int bit_disp = j * new_font->glyphs[i].width;
        for (unsigned int k = 0; k < new_font->glyphs[i].width; k++) {
            full_texture[(full_disp + k)] =
                    glyph_textures[i][bit_disp + k];
        }
    }
}

然后我加载纹理数据调用:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->x, texture->y, 0, GL_RED, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(full_texture));

我的片段着色器执行以下代码:

#version 330

uniform sampler2D texture;

in vec2 texcoord;
in vec4 pass_colour;

out vec4 out_colour;

void main()
{
float temp = texture2D(texture, texcoord).r;
out_colour = vec4(pass_colour[0], pass_colour[1], pass_colour[2], temp);
}

我得到一张我能说出来的图像是从纹理生成的,但却非常扭曲,我不确定为什么。顺便说一下,我正在使用GL_RED,因为从Opengl 4中删除了GL_ALPHA。 让我感到困惑的是,当我从字形生成4 RGBA纹理然后使用它的alpha通道时,为什么这样可以正常工作?

2 个答案:

答案 0 :(得分:15)

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->x, texture->y, 0, GL_RED, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(full_texture));

这在技术上是合法的,但从不是一个好主意。

首先,您需要了解glTexImage2D的第三个参数是什么。这是纹理的实际image format。您不是使用一个通道创建纹理;你正在使用四个频道创建一个纹理。

接下来,您需要了解最后三个参数的作用。这些是pixel transfer parameters;它们描述了你给OpenGL的像素数据是什么样的。

这个命令说,“创建一个4通道纹理,然后将一些数据上传到只是红色通道。这些数据存储为无符号字节数组。”将数据上传到纹理通道的某些在技术上是合法的,但几乎从来不是一个好主意。如果您要创建单通道纹理,则应使用单通道纹理。这意味着适当的图像格式。

接下来,事情变得更加混乱:

new_texture->datasize = texture_width * texture_height*4;

您使用“* 4”强烈建议您创建四通道像素数据。但您只需上传单通道数据。其余的计算都同意这一点;你似乎没有填写任何数据传递full_texture[texture_width * texture_height]。所以你可能会分配比你需要的更多的内存。

最后一件事:总是使用大小的内部格式。永远不要只使用GL_RGBA;使用GL_RGBA8GL_RGBA4或其他。不要让司机挑选并希望它给你一个好的。

所以,正确上传就是这样:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, texture->x, texture->y, 0, GL_RED, GL_UNSIGNED_BYTE, full_texture);

仅供参考:reinterpret_cast是不必要的;即使在C ++中,指针也可以隐式转换为void*

答案 1 :(得分:3)

我认为您交换了glTexImage2d()的“内部格式”和“格式”参数。也就是说,你告诉它你想在纹理对象中使用RGBA,但在文件数据中只有RED而不是反之亦然。

尝试使用以下内容替换您的电话:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, texture->x, texture->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(full_texture));