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

Kac*_*llo 3 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];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

#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);
}
Run Code Online (Sandbox Code Playgroud)

我得到一个我可以告诉的图像是从纹理生成的,但它非常扭曲,我不确定为什么.顺便说一下,我正在使用GL_RED因为从Opengl 4中删除了GL_ALPHA.真正令我困惑的是为什么当我从字形生成4 RGBA纹理然后使用它的alpha通道时这种工作正常?

Nic*_*las 15

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

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

首先,您需要了解第三个参数glTexImage2D是什么.这是纹理的实际图像格式.您不是使用一个通道创建纹理; 你正在创建一个有四个通道的纹理.

接下来,您需要了解最后三个参数的作用.这些是像素传输参数 ; 他们描述了你给OpenGL的像素数据是什么样的.

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

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

new_texture->datasize = texture_width * texture_height*4;
Run Code Online (Sandbox Code Playgroud)

您使用"*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);
Run Code Online (Sandbox Code Playgroud)

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


Dre*_*all 4

我认为您交换了 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));
Run Code Online (Sandbox Code Playgroud)