从位图加载纹理

时间:2013-11-30 08:48:17

标签: c++ visual-c++ opengl freeimage

看来我正在加载错误的图像。图像看起来都是乱七八糟的。我在这做错了什么?

int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
    glLoadIdentity();   // Reset The Current Modelview Matrix

    glEnable(GL_TEXTURE_2D);
    GLuint texture = 0;
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D, texture);

    FIBITMAP* bitmap = FreeImage_Load(FreeImage_GetFileType("C:/Untitled.bmp", 0), "C:/Untitled.bmp", BMP_DEFAULT);
    FIBITMAP *pImage = FreeImage_ConvertTo32Bits(bitmap);
    int nWidth = FreeImage_GetWidth(pImage);
    int nHeight = FreeImage_GetHeight(pImage);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nWidth, nHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(pImage));
    FreeImage_Unload(pImage);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, -1.0f);
    glEnd();

    RECT desktop;
    const HWND hDesktop = GetDesktopWindow();
    GetWindowRect(hDesktop, &desktop);
    long horizontal = desktop.right;
    long vertical = desktop.bottom;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glDisable(GL_TEXTURE_2D);
    return TRUE;    // Keep Going
}

我在程序运行时看到的内容 What i see when the program runs 程序运行时我希望看到的内容(我正在加载位图) What i expect to see

2 个答案:

答案 0 :(得分:3)

这里的部分问题似乎是你从FreeImage获得的像素数据的格式与glTexImage2D所期望的格式之间的不匹配。

FreeImage_ConvertTo32Bits将返回包含32位像素数据的图像。我没有使用FreeImage,但通常这意味着每个像素将有4个8位组件,分别代表红色,绿色,蓝色和alpha(不透明度)。从BMP文件获取的数据格式取决于文件,可能有也可能没有alpha通道。但是,如果您的原始图像完全不透明(因为您的BMP文件格式缺少Alpha通道或者因为您在创建文件时将其设置为不透明),FreeImage_ConvertTo32Bits将返回alpha设置为255的数据似乎是安全的)。

这一切都很好,但问题来自对glTexImage2D的调用。此功能可以采用多种不同格式的像素数据。它用于解释数据的格式由参数typeformat确定为here。代码中format的值为GL_RGB。这表示每个像素有三个组件描述其在像素数据中按此顺序出现的红色,绿色和蓝色分量。 typeGL_UNSIGNED_BYTE)的值表示每个组件的大小为单个字节。问题是缺少alpha通道,因此glTexImage2D从错误的位置读取像素数据。另外,正如Roger Rowland所指出的那样,FreeImage产生的颜色顺序似乎是蓝绿红色。修复很简单:将format设置为GL_BGRA,告诉glTexImage2D有关alpha组件和数据顺序的信息:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nWidth, nHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(pImage));

要查看此问题是否可以解释奇怪的输出,请考虑原始图像中的大块蓝色。根据GIMP,这在很大程度上是蓝色的,绿色较少(R = 0,G = 162,B = 232)。所以我们有这样的事情:

B G R A B G R A B G R A ...   meaning of bytes from FreeImage_GetBits
1 - 0 1 1 - 0 1 1 - 0 1 ...   "values" of bytes (0 -> 0, - -> 162, 1 -> 232 or 255)
R G B R G B R G B R G B ...   what glTexImage2D thinks the bytes mean

这里的纹理像素颜色是:橙色,浅黄色,明亮的青色和紫色。这些重复是因为读取4个像素消耗12个字节,这恰好等于3个原始像素。这解释了您在大部分输出图像上看到的模式。 (最初我使用RGBA订单进行了此操作,但GBRA版本更适合图像 - 差异在行的开头特别明显。)

但是我必须承认,我不确定一开始会发生什么,以及如何将它与粉红色方块联系起来!所以这里可能还有其他问题,但希望使用GL_BGRA将是朝着正确方向迈出的一步。

答案 1 :(得分:2)

您正在制作32 bpp图像,因此您需要具有正确的纹理声明:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, nWidth, nHeight,
    0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(pImage));

此外,FreeImage_GetBits函数返回通常对齐的数据,以便每行以4字节边界结束。因此,如果你的图像是32 bpp(就像你的那样),或者你的图像宽度是2的幂,那就没问题,但是否则,你需要适当地设置解压缩对齐。