我有一些加载纹理的代码,我使用 DevIL 加载图像,然后 OpenGL 从像素创建纹理。这段代码工作正常,纹理正确显示,这一切都很好。
除此之外,我还可以在程序中创建一个数组来创建纹理或直接更改纹理的像素。我的问题在这里:在处理像素时,它们的格式似乎是 ABGR 而不是我希望的 RGBA。
我偶然发现了这个 SO 问题,它指的是 glTexImage2D 函数中传递的格式:
(...) 如果您有 GL_RGBA 和 GL_UNSIGNED_INT_8_8_8_8,这意味着像素存储在 32 位整数中,并且颜色在这样的整数中按照逻辑顺序 RGBA,例如红色在高位字节中,而alpha 在低位字节中。但是如果机器是 little-endian(如 Intel CPU),那么内存中的实际顺序是 ABGR。而 GL_RGBA 和 GL_UNSIGNED_BYTE 将以 RGBA 顺序存储字节,无论计算机是小端还是大端。(...)
事实上,我有一个英特尔 CPU。图像以现在的方式加载得很好,我实际上使用 GL_RGBA 模式和 GL_UNSIGNED_BYTE 类型。
GLuint makeTexture( const GLuint* pixels, GLuint width, GLuint height ) {
GLuint texture = 0;
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glBindTexture( GL_TEXTURE_2D, NULL );
GLenum error = glGetError();
if ( error != GL_NO_ERROR ) {
return 0;
}
return texture;
}
这个函数用在我的两种加载纹理的方法中,一种是从文件加载图像的方法,另一种是从数组创建纹理的方法。
假设我想创建一个像素数组并创建一个纹理,
GLuint pixels[ 128 * 128 ];
for ( int i = 0; i < 128 * 128; ++i ) {
pixels[ i ] = 0x800000FF;
}
texture.loadImageArray( pixels, 128, 128 );
通过用这个值填充像素,我希望看到稍微深红色的颜色。
red = 0x80, green = 0x00, blue = 0x00, alpha = 0xFF
但相反,我得到一个透明的红色,
alpha = 0x80, blue = 0x00, green = 0x00, red = 0xFF
我没有使用原始无符号整数,而是创建了一个结构来帮助我处理单个通道:
struct Color4C {
unsigned char alpha;
unsigned char blue;
unsigned char green;
unsigned char red;
...
};
我可以很容易地用 Color4C 数组替换一个无符号整数数组,结果是一样的。如果我反转通道的顺序(首先是红色,最后是 alpha),那么我可以轻松地传递 0xRRGGBBAA 并使其工作。
简单的解决方案是以 ABGR 格式简单地处理这些值。但我也发现使用 RGBA 值更容易。如果我想使用硬编码的颜色值,我更愿意将它们写成 0xRRGGBBAA 而不是 0xAABBGGRR。
但是假设我开始使用 ABGR 格式。如果我要在另一台机器上运行我的代码,我会在直接更改像素/通道的地方突然看到奇怪的颜色吗?有更好的解决方案吗?