2012-03-24 69 views
2

我想要做的是从单通道数据数组中加载纹理到硬件中,并使用它的alpha通道将文本绘制到对象上。我使用的是opengl 4.Opengl:使用单通道纹理作为alpha通道来显示文本

如果我尝试使用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通道?

+0

最后,我通过在调用glTexImage2D之前将数据转换为float来完成此工作。我相信我需要使用4字节倍数的数据格式。这就是为什么RGBA转RGBA的原因(即使它是4x字节)以及为什么浮动数据也起作用。看来我无法使用GL_UNSIGNED_BYTE,除非它具有4通道数据的输入和输出。也许这是ATI驱动程序中的一个错误? – 2012-03-24 05:16:14

+1

好吧,我已经明白了这一点。我的代码没有错,也没有驱动程序中的错误。 GL_UNPACK_ALINGMENT需要设置为1才能工作。它默认设置为4。运行“glPixelStorei(GL_UNPACK_ALIGNMENT,1);”解决了我所有的问题。由于性能原因,我不确定它为什么设置为4。我会调查。 – 2012-03-24 05:27:36

回答

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

我的场景是红色的,RGBA中的内部数据。如果我交换它们更糟。我也尝试将内部文件数据设置为红色,它仍然显示相同...我甚至尝试了两个通道,并且不起作用... – 2012-03-24 03:44:09

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

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

+0

嗨,感谢您的信息。 4是我在加载4个通道和1个通道之间来回切换时的错字。发帖时我搞砸了,我会编辑帖子。我已经应用了所有建议,不幸的是我仍然可以获得相同的效果。 – 2012-03-24 03:56:41

+0

这非常奇怪,当我从4通道数据螺母创建4通道纹理时,如果我尝试从4通道数据创建1通道纹理,它仍会混乱起来,我会得到适当的效果!这至少告诉我这个问题不是输入数据,并且必须位于从一种数据到另一种数据的转换中,或者在我的着色器代码中。 – 2012-03-24 04:16:17

相关问题