4

我有一些加载纹理的代码,我使用 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 格式。如果我要在另一台机器上运行我的代码,我会在直接更改像素/通道的地方突然看到奇怪的颜色吗?有更好的解决方案吗?

4

1 回答 1

0

对答案提出一些有用的评论:

0xRR,0xGG,0xBB,0xAA在您的(英特尔,little-endian)机器上是0xAABBGGRR. 您已经发现信息表明 GL_UNSIGNED_BYTE 保留跨机器数据块的二进制格式,同时GL_UNSIGNED_INT_8_8_8_8保留文字的格式,如0xRRGGBBAA. 因为不同的机器对二进制和字面量的对应关系不同,所以你绝对不可能同时拥有两种类型的可移植性。——本·沃伊特

[0xAABBGGRR在你的机器上写实际上是 RGBA,但在另一台机器上运行这段代码可能会显示不同的结果] 因为 OpenGL 会将它重新解释为UNSIGNED_BYTE. 毕竟,C++ 需要一个字节顺序库。– WorldSENDer

于 2022-01-31T17:35:17.867 回答