纹理在OpenGL中呈现非常奇怪

时间:2013-10-11 12:24:39

标签: c++ opengl textures

我正在尝试在OpenGL中绘制一个框(顶部是打开的)。我给它纹理,但它们似乎非常古怪。当我旋转盒子时,侧面纹理似乎在底部,而不是。

这是前视图:

Front view

旋转一下后:

Rotated view

显然,这里出了点问题。蓝色的是侧面板的纹理,但是当它旋转时,它似乎在地板上。灰色的是前面板的纹理。因此,在前视图中,后面板根本不应该是可见的。但是,可以看出它。

代码段:

绘制容器的方法(不包括盖子):

void box::drawContainer() {
    GLuint tex = loadTexture("wood.bmp");
    glPushMatrix();

    glBindTexture(GL_TEXTURE_2D, tex);
    drawBlock(vertex(0, 0, 0), length + 0.2, length + 0.2, thickness); // bottom

    tex = loadTexture("tiles.bmp");
    glBindTexture(GL_TEXTURE_2D, tex);
    drawBlock(
            vertex((length - thickness) / 2.0,
                    (containerHeight + thickness) / 2.0, 0), thickness, breadth,
            containerHeight); // right

    tex = loadTexture("ocean.bmp");
    glBindTexture(GL_TEXTURE_2D, tex);
    drawBlock(
            vertex((thickness - length) / 2.0,
                    (containerHeight + thickness) / 2.0, 0), thickness, breadth,
            containerHeight); // left

    tex = loadTexture("smoke.bmp");
    glBindTexture(GL_TEXTURE_2D, tex);
    drawBlock(
            vertex(0, (containerHeight + thickness) / 2.0,
                    (breadth - thickness) / 2.0), (length - 2.0 * thickness),
            thickness, containerHeight); // front

    tex = loadTexture("lightning.bmp");
    glBindTexture(GL_TEXTURE_2D, tex);
    drawBlock(
            vertex(0, (containerHeight + thickness) / 2.0,
                    (thickness - breadth) / 2.0), (length - 2.0 * thickness),
            thickness, containerHeight); // back

    glPopMatrix();
}

drawBlock方法:

void object::drawBlock(vertex center, float length, float breadth,
        float height) {
    glPushMatrix();
    glTranslatef(center.x, center.y, center.z);
    glScalef(length, height, breadth);
    glBegin(GL_QUADS);
    drawPrimitive(vertex(-0.5, 0.5, 0.5), vertex(-0.5, -0.5, 0.5),
            vertex(0.5, -0.5, 0.5), vertex(0.5, 0.5, 0.5),
            vertex(-0.5, 0.5, -0.5), vertex(-0.5, -0.5, -0.5),
            vertex(0.5, -0.5, -0.5), vertex(0.5, 0.5, -0.5));
    glEnd();
    glPopMatrix();
}

drawPrimitive方法:

void object::drawPrimitive(vertex v1, vertex v2, vertex v3, vertex v4,
        vertex v5, vertex v6, vertex v7, vertex v8) {
    drawFace(v1, v2, v3, v4);
    drawFace(v5, v6, v7, v8);
    drawFace(v1, v5, v6, v2);
    drawFace(v4, v3, v7, v8);
    drawFace(v1, v4, v8, v5);
    drawFace(v2, v6, v7, v3);
}

并且,drawFace方法:

void object::drawFace(vertex v1, vertex v2, vertex v3, vertex v4) {
    glTexCoord2f(0, 1);
    glVertex3f(v1.x, v1.y, v1.z);
    glTexCoord2f(0, 0);
    glVertex3f(v2.x, v2.y, v2.z);
    glTexCoord2f(1, 0);
    glVertex3f(v3.x, v3.y, v3.z);
    glTexCoord2f(1, 1);
    glVertex3f(v4.x, v4.y, v4.z);
}

主要功能:

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
    glutInitWindowSize(640, 480);
    glutInitWindowPosition(50, 50);
    glutCreateWindow(title);

    glutDisplayFunc(display);

    glutKeyboardFunc(processKey);

    glutReshapeFunc(reshape);
    initGL();
    glutMainLoop();
    return 0;
}

initGL方法:

void initGL() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
    glClearDepth(1.0f);                   // Set background depth to farthest
    glEnable(GL_DEPTH_TEST);   // Enable depth testing for z-culling
    glDepthFunc(GL_LEQUAL);    // Set the type of depth-test
    glShadeModel(GL_FLAT);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Nice perspective corrections
}

loadTexture方法:

GLuint inline loadTexture(const char* fName) {
    // Data read from the header of the BMP file
    unsigned char header[54]; // Each BMP file begins by a 54-bytes header
    unsigned int dataPos;   // Position in the file where the actual data begins
    unsigned char * data;
    unsigned int imageSize;
    unsigned int width, height;
    // Actual RGB data
    // Open the file
    FILE * file = fopen(fName, "rb");
    if (!file) {
        printf("Image could not be opened\n");
    }
    if (fread(header, 1, 54, file) != 54) { // If not 54 bytes read : problem
        printf("Not a correct BMP file\n");
        return 0;
    }
    if (header[0] != 'B' || header[1] != 'M') {
        printf("Not a correct BMP file\n");
        return 0;
    }
    // Read ints from the byte array
    dataPos = *(int*) &(header[0x0A]);
    imageSize = *(int*) &(header[0x22]);
    width = *(int*) &(header[0x12]);
    height = *(int*) &(header[0x16]);

    // Some BMP files are misformatted, guess missing information
    if (imageSize == 0)
        imageSize = width * height * 3; // 3 : one byte for each Red, Green and Blue component
    if (dataPos == 0)
        dataPos = 54;
    // Create a buffer
    data = new unsigned char[imageSize];

    // Read the actual data from the file into the buffer
    fread(data, 1, imageSize, file);

    //Everything is in memory now, the file can be closed
    fclose(file);
    // Create one OpenGL texture
    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR,
            GL_UNSIGNED_BYTE, data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    return textureID;
}

调用drawContainer的draw方法:

void box::draw()
{
        glEnable(GL_TEXTURE_2D);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
        drawContainer();
        glDisable(GL_TEXTURE_2D);
}

请告诉我是否需要插入更多代码或需要删除任何内容。

5 个答案:

答案 0 :(得分:2)

在其他答案中已经说过了,虽然我认为GL_DEPTH_TEST未启用会出现问题。

但是,我确实看到您的代码包含以下内容:

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

上下文问题

我认为问题在于你实际上没有为深度缓冲区分配/给出任何内存。因此,GL_DEPTH_TEST无法执行。

虽然我可以看到你实际上说:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

请记住:您需要传递GLUT_DEPTH而不是GL_DEPTH等等。(我这样说,以防其他任何人面临同样的问题你,这通常是一个常见的错误)

您是否尝试过使用:

glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);

硬件问题

问题可能还在于您在计算机上使用的硬件,某些硬件不支持32位深度缓冲区,因此您可以使用24位等深度缓冲区。

透视问题

我没有在您的代码中看到实际设置透视图的任何位置,这也可能是深度测试混乱的原因。因为如果你在透视投影矩阵中使用0.0作为近平面,那么它可能会破坏深度测试。

我为这个公开的答案道歉,但我现在无法对此进行测试。此外,如果由于您的硬件而发生,那么我/我们无法测试它。

答案 1 :(得分:0)

你似乎错过了

glEnable(GL_DEPTH_TEST);

另外,请确保您的OpenGL上下文具有深度缓冲区(这取决于平台;因为您没有显示如何创建上下文窗口,所以我无法向您展示如何执行此操作)。

最后,请务必将GL_DEPTH_BUFFER_BIT传递给glClear,无论您在何处召唤它。

答案 2 :(得分:0)

您的代码不完整,所以这只是猜测。 (你没有显示loadTexture)

我没有看到你启用和禁用纹理的位置,因此最后一个活动纹理将用于渲染的其余部分,可能会导致问题。

使用纹理的正确顺序是启用它,绑定到纹理,渲染,然后禁用纹理。像这样:

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
// render here
glDisable(GL_TEXTURE_2D);

OpenGL common mistakes可以帮助您解决问题。


如果你使用box::drawContainer()来渲染图像,那么你就是错误地做了,因为每次渲染窗口时你都要创建新的纹理。你需要做一次,然后只使用纹理。当不需要纹理时,您可以释放它们。

答案 3 :(得分:0)

您似乎永远不会清除颜色/深度缓冲区。你需要在每一帧之前完成它。此外,请确保在跟踪容器时仍然启用了深度测试:

glIsEnabled( GL_DEPTH_TEST );

如果没有,请查看您尚未发布的代码。

希望这有帮助

答案 4 :(得分:0)

原来我给了z-perspective错误。感谢所有帮助