glReadPixels交换蓝色和红色

Joa*_*cho 0 opengl sdl-image

我正在尝试将opengl中的屏幕区域保存到位图中.我尝试过使用FreeImage和SDL_Image,它们都要求我交换红色和蓝色通道.当然,这让我怀疑glReadPixels是这里的问题......我有这个示例代码:

bool CaptureScreenRegionToFile ( uint32_t In_X, uint32_t In_Y, uint32_t In_Width, uint32_t In_Height, std::string In_Filename )
{
GLubyte* ImageData = ( GLubyte* ) malloc ( In_Width * In_Height * 3 );
glPixelStorei ( GL_PACK_ALIGNMENT, 1 );
glReadPixels ( In_X, In_Y, In_Width, In_Height, GL_RGB, GL_UNSIGNED_BYTE, ImageData );

if ( CheckError() == false )
    {
    free ( ImageData );
    return false;
    }

SDL_Surface *Surface;

// JTP TODO Known bug here. Red and blue are swapped, for some reason...
Surface = SDL_CreateRGBSurfaceFrom ( ImageData, In_Width, In_Height, 3 * 8, In_Width * 3, 0x00FF0000, 0x0000FF00, 0x000000FF, 0 );
SDL_SaveBMP ( Surface, In_Filename.c_str() );
SDL_FreeSurface ( Surface );
free ( ImageData );

return true;
}
Run Code Online (Sandbox Code Playgroud)

除非我在调用CreateRGBSurfaceFrom后手动交换红色和蓝色通道,否则它的颜色将在BMP上交换.glReadPixels应该这样做吗?我是否正确称呼它?这有什么不对?

der*_*ass 9

glReadPixels完美的工作,因为它的意图.当您将数据读回时GL_RGB,您将在内存中获得以下布局

 0 1 2 3 4 5 6 7 8  
+---------------------+
|R|G|B|R|G|B|R|G|B|...|
+---------------------+
Run Code Online (Sandbox Code Playgroud)

现在你使用SDL_CreateRGBSurfaceFrom每像素24位.这将把每组3个字节解释为一个像素.但是,它会将此作为一个大的整数,用rmask,gmask,bmask和`AMASK.描述哪些位属于哪个图像通道的参数.

例如,您使用0x00FF0000红色掩码,意味着位16到23将包含读取(从最低有效位计数,从零开始):

 3      2|       1|       0|        0    bit 
 1      4|       6|       8|        0   number
+-----------------------------------+
|00000000|11111111|00000000|00000000|
+-----------------------------------+
  byte 3   byte 2   byte 1   byte 0
Run Code Online (Sandbox Code Playgroud)

但是,您最有可能使用小端机器,其中最低有效字节存储在最低内存位置.这意味着您rmask将被存储为:

  0    1    2    byte number
+--------------+
+ 00 | 00 | FF |
+--------------+
  R    G     B
Run Code Online (Sandbox Code Playgroud)

所以它与您从中读取像素数据的格式不匹配.另请注意,您的代码不可移植,您将在大端架构上获得不同(意图)的结果.

更新1

如果您希望尽可能将此代码编写为protable,而不添加一些endian-dependend #ifdefs,则不能使用每像素3个字节的格式.但是,您可以使用GL_UNSIGNED_INT_8_8_8_8GL_UNSIGNED_INT_8_8_8_8_REV,其中每个像素被视为32位整数,并使用机器的本机字节顺序存储.该_REV变种会保存您的格式的第一个组件(例如,红色GL_RGBA在最显著字节),非_REV变异最显著字节.在任何一种情况下,您都可以设置适当的掩码,它将独立于字节序.