使用 Glut 和 C 时扭曲的纹理

Posted

技术标签:

【中文标题】使用 Glut 和 C 时扭曲的纹理【英文标题】:Distorted Texture when using Glut and C 【发布时间】:2017-10-17 08:01:23 【问题描述】:

我正在努力让自己熟悉 XCode 9 中的 GLUT 框架,以便在未来的项目中进行工作,但现在我无法让纹理正确显示。

所以我的目标是将此 bmp 图像显示为纹理:

到这个红色方块所在的位置:

结果是这样的:

什么时候应该是这样的:

这是我用于初始化纹理的代码。

GLuint loadAndBufferImage(const char * filename)

    GLuint texture;
    unsigned char header[54];
    unsigned int dataPos;
    unsigned int width, height;
    unsigned int imageSize;

    unsigned char * data;

    FILE * file = fopen(filename, "rb");
    if(!file)printf("Image could not load\n"); exit(2);

    if(fread(header, 1, 54, file) != 54)
        printf("Not a correct BMP file.\n");
        return -1;
    

    if(header[0] != 'B' || header[1] != 'M')
        printf("Not a correct BMP file.\n");
        return -1;
    

    dataPos = *(int*)&(header[0x0A]);
    imageSize = *(int*)&(header[0x22]);
    width = *(int*)&(header[0x12]);
    height = *(int*)&(header[0x16]);

    if(imageSize == 0) imageSize = width * height * 4;
    if(dataPos==0) dataPos=54;

    data = malloc(imageSize);
    if(!data)printf("No more memory\n"); exit(1);

    fread(data, 1, imageSize, file);
    fclose(file);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    free(data);
    return texture;    

这就是调用该函数的地方。

GameWindow *initializeGameWindow()


    GameWindow *gw = malloc(sizeof(*gw));
    if(gw == NULL)
        printf("Error: no more memory");
        exit(1);
    

    gw->render = render;
    gw->update = update;
    gw->isRunning = isRunning;
    gw->setRunning = setRunning;
    glClearColor(1.0, 1.0, 1.0, 1.0);

    glEnable(GL_TEXTURE_2D);

    glViewport(0.0f, 0.0f, _width, _height);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0, _width, 0, _height);
    glMatrixMode(GL_MODELVIEW);

    glGenBuffers(1, &_vertexBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, sizeof(VertexData), (GLvoid *)offsetof(VertexData, pos));


    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, sizeof(VertexData), (GLvoid *)offsetof(VertexData, tex));

    _textureBufferID = loadAndBufferImage("test.bmp");

    return gw;

我要猜测一下,这与我如何从图像中获取数据以及可能的纹理参数有关。如果是这样,那么我该如何解决这个问题?否则我还需要做些什么来设置纹理吗?

编辑: 所以我按照建议在纹理初始化代码中的fread(data, 1, imageSize, file); 上方添加了fseek(file, (long)dataPos, SEEK_SET);,与初始结果相比,它似乎稍微改变了图像。

我还尝试将 GL_RGBA 和 GL_BGRA 分别更改为 glTexImage2D 函数中的 GL_RGB 和 GL_BGR 并且发生了这种情况。

编辑 2: 所以经过一些研究和实验后,发现另一个问题是因为当我将图像保存为位图时,图像被设置为 indexed color mode 而不是 RGB color mode文件。 (我正在使用 Gimp 编辑器。)它一定影响了数据的存储方式,因为当我比较它们时,文件像素数据部分中的十六进制值和总文件大小不同。但在编辑器中将其切换为 RBG 颜色模式是解决此问题的最后关键。

https://image.ibb.co/fC99Lm/Screen_Shot_2017_10_18_at_4_15_36_AM.png

感谢您的所有帮助。

资源:

https://en.wikipedia.org/wiki/BMP_file_format

http://fac.ksu.edu.sa/sites/default/files/lab08_6.pdf

【问题讨论】:

您确定 BMP 文件中有 Alpha 通道数据吗?您将数据作为 RGBA 传递给纹理(我的意思是调用 glTexImage2D)。 我尝试按照建议更改 glTexImage2D 函数(分别更改为 GL_RGB 和 GL_BGR)并发布了结果。我认为颜色数据的长度是 4 个字节而不是 3 个。 【参考方案1】:

您已阅读但忽略了dataPos,图像数据的偏移量。使用

fseek(file, (long)dataPos, SEEK_SET);
fread(data, 1, imageSize, file);

将文件指针定位到数据。其原因是,标题和图像数据之间可以存在调色板数据。

【讨论】:

我只是按照您的建议进行了尝试,与最初的结果相比,它似乎稍微改变了图像。 我建议你阅读一下BMP file format。这很复杂。在BITMAPINFOHEADER 中是偏移量0x1C(有时称为WORD biBitCount)的2 字节字段,它给出了每个像素的位数。您可以通过将文件大小与图像尺寸乘以 3 或乘以 4 进行比较来粗略评估。

以上是关于使用 Glut 和 C 时扭曲的纹理的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 和 GLUT/C++ 奇怪的纹理循环问题

使用 GLUT 在立方体上的 OpenGL 多纹理映射

如何纹理 Opengl glut 对象(C++)

通过 Glut 为 OpenGL 自定义纹理映射

从位图图像中读取2D纹理(C ++,OpenGL)

如何使用 GLUT 在按键上的纹理/帧缓冲区之间切换?