我要做的是从单通道数据数组将纹理加载到硬件中,并使用它的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(GL_TEXTURE_2D, 0, GL_RGBA, texture->x, texture->y, 0, GL_RED, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(full_texture));
这在技术上是合法的,但从来都不是一个好主意。
首先,您需要了解glTexImage2D
的第三个参数是什么。这是纹理的实际图像格式。您不是在用一个通道创建纹理;您正在创建一个具有四个通道的纹理。
接下来,你需要了解最后三个参数的作用。它们是像素转移参数;它们描述了您提供给OpenGL的像素数据的样子。
这个命令说,"创建一个4通道纹理,然后将一些数据上传到红色通道。这些数据存储为无符号字节数组。"从技术上讲,只将数据上传到纹理的一些通道是合法的,但几乎从来都不是一个好主意。如果要创建单通道纹理,则应使用单通道纹理。这意味着一个合适的图像格式。
接下来,事情变得更加混乱:
new_texture->datasize = texture_width * texture_height*4;
您使用"*4"强烈表明您正在创建四通道像素数据。但你只上传了一个频道的数据。你的其余计算与此一致;您似乎从未填写过任何数据传递full_texture[texture_width * texture_height]
。所以你可能分配的内存比你需要的要多。
最后一件事:总是使用大小的内部格式。千万不要只使用GL_RGBA
;使用CCD_ 4或CCD_。不要让司机挑毛病,希望它能给你一个好的。
因此,正确的上传方式是:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, texture->x, texture->y, 0, GL_RED, GL_UNSIGNED_BYTE, full_texture);
仅供参考:reinterpret_cast
是不必要的;即使在C++中,指针也可以隐式地转换为void*
。
我认为您交换了glTexImage2d()的"内部格式"one_answers"格式"参数。也就是说,您告诉它您希望在纹理对象中使用RGBA,但在文件数据中只有RED,反之亦然。
尝试用以下内容替换您的呼叫:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, texture->x, texture->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(full_texture));