我正在尝试做的是从单 channel 数据数组将纹理加载到硬件中,并使用它的 alpha channel 将文本绘制到对象上。我正在使用 opengl 4。
如果我尝试使用 4 channel RGBA 纹理来执行此操作,它工作得非常好,但无论出于何种原因,当我尝试仅在单个 channel 中加载时,我得到的是乱码图像,我无法弄清楚原因。 我通过使用以下代码将一系列字形的纹理位图数据组合成单个纹理来创建纹理:
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 channel 时,为什么它可以正常工作??
最佳答案
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的质地。您不是用一个 channel 创建纹理;您正在创建具有四个 channel 的纹理。
接下来,您需要了解最后三个参数的作用。这些是 pixel transfer parameters ;它们描述了您提供给 OpenGL 的像素数据是什么样的。
这个命令是说,“创建一个 4 channel 纹理,然后上传一些数据到只是红色 channel 。这个数据被存储为一个无符号字节数组。”仅将数据上传到纹理的某些 channel 在技术上是合法的,但几乎不是一个好主意。如果您要创建单 channel 纹理,则应使用单 channel 纹理。这意味着正确的图像格式。
接下来,事情变得更加困惑:
new_texture->datasize = texture_width * texture_height*4;
您对“*4”的使用强烈暗示您正在创建四 channel 像素数据。但是您只上传单 channel 数据。您的其余计算都同意这一点;您似乎从未填写过任何数据 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*
。
关于c++ - Opengl:使用单 channel 纹理作为 alpha channel 来显示文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9848901/