【问题标题】:Opengl: Use single channel texture as alpha channel to display textOpengl:使用单通道纹理作为 Alpha 通道来显示文本
【发布时间】:2012-04-08 14:03:23
【问题描述】:

我要做的是将纹理从单通道数据数组加载到硬件中,并使用它的 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,因为 GL_ALPHA 已从 Opengl 4 中删除。 真正让我感到困惑的是,为什么当我从字形生成 4 RGBA 纹理然后使用它的 Alpha 通道时它可以正常工作??

【问题讨论】:

  • 最后,我通过在调用 glTexImage2D 之前将数据转换为浮点数来实现这一点。我相信我需要使用 4 个字节的倍数的数据格式。这就是为什么 RGBA 到 RGBA 有效(即使它是 4x 字节)以及浮点数据也有效的原因。似乎我无法使用 GL_UNSIGNED_BYTE 除非它同时具有 4 通道数据的输入和输出。也许这是 ATI 驱动程序中的错误??
  • 好的,我知道了。我的代码没有任何问题,驱动程序中也没有错误。 GL_UNPACK_ALINGMENT 需要设置为 1 才能工作。默认设置为 4。运行“glPixelStorei(GL_UNPACK_ALIGNMENT, 1);”解决了我所有的问题。我不确定为什么将其设置为 4 可能是出于性能原因。我会调查的。

标签: c++ opengl text opengl-4


【解决方案1】:
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_RGBA8 或GL_RGBA4 或其他。不要让司机挑,希望它给你一个好的。

所以,正确的上传应该是这样的:

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

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

【讨论】:

  • 您好,感谢您的信息。当我在加载 4 个通道和 1 个通道之间来回切换时,4 是一个错字。我发帖时搞砸了,我会编辑帖子。我已经采纳了你的所有建议,不幸的是我仍然得到了同样的效果。
  • 很奇怪,当我从 4 通道数据创建 4 通道纹理时,如果我尝试从 4 通道数据创建 1 通道纹理,它仍然会搞砸!这至少告诉我问题不在于输入数据,而必须位于从一种数据类型转换为另一种数据类型或在我的着色器代码中的下游。
【解决方案2】:

我认为您交换了 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));

【讨论】:

  • 我的文件数据是红色,内部数据是 RGBA。如果我交换它们,那就更糟了。我还尝试将内部文件数据都设置为 RED,但它仍然显示相同...我什至尝试接收两个通道,但效果不佳...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-18
相关资源
最近更新 更多