2

我正在尝试在 OpenGL 中绘制一个框(顶部打开)。我给了它纹理,但它们似乎渲染得很奇怪。当我旋转盒子时,侧面纹理有时会出现在底部,什么不是。

这是前视图:

正视图

稍微旋转一下后:

旋转视图

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

代码片段:

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

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
}

加载纹理方法:

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);
}

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

4

5 回答 5

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在透视投影矩阵中使用近平面,那么它可能会弄乱深度测试。

对于开放的答案,我深表歉意,但我现在无法对此进行测试。此外,如果它是由于您的硬件而发生的,那么我/我们无法对其进行测试。

于 2013-10-11T14:48:34.723 回答
0

您似乎从未清除过颜色/深度缓冲区。您需要在每一帧之前执行此操作。此外,请确保在跟踪容器时仍启用深度测试:

glIsEnabled( GL_DEPTH_TEST );

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

希望这可以帮助

于 2013-10-11T16:39:46.017 回答
0

你似乎错过了一个

glEnable(GL_DEPTH_TEST);

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

最后,确保传递GL_DEPTH_BUFFER_BITglClear您所称的任何地方。

于 2013-10-11T12:32:05.730 回答
0

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

我看不到您在哪里启用和禁用纹理,因此最后一个活动纹理将用于其余的渲染,可能会导致问题。

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

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

OpenGL 常见错误可能会帮助您解决问题。


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

于 2013-10-11T12:53:34.470 回答
0

原来我把 z 透视图弄错了。感谢所有的帮助

于 2013-11-06T11:16:00.597 回答