Question

I started learning OpenGL and I'm using it with SFML 2.1 to get window, load images, etc. But I've got a problem with simple prism. Faces are partly transparent and it looks terrible :/ I was looking at tutorials, but I don't know what is wrong with my code... Could you help me? I read that it's problem with Z-Buffering. How to fix it?

Here is my code:

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics.hpp>

using namespace std;

void drawCube (float x, float y, float z, float width, float height, GLuint Texture);

int main()
{
    // Window
    sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL", sf::Style::Default, sf::ContextSettings(32));

    // Camera
    GLdouble eyex = 0;
    GLdouble eyey = 0;
    GLdouble eyez = 2575;

    GLuint Texture = 0;
    {
        sf::Image Image;
        if (!Image.loadFromFile("background.png"))
            return EXIT_FAILURE;
        glGenTextures(1, &Texture);
        glBindTexture(GL_TEXTURE_2D, Texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Image.getSize().x, Image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, Image.getPixelsPtr());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    }

    // Main loop
    while (window.isOpen())
    {
        // Checking events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close the window
            if (event.type == sf::Event::Closed)
                window.close();

            // Resize the window
            if (event.type == sf::Event::Resized)
                glViewport(0, 0, event.size.width, event.size.height);
        }

        // Close the window
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
            window.close();

        // Clear the window
        window.clear(sf::Color::White);

        // Viewport
        glViewport( 0, 0, window.getSize().x, window.getSize().y );

        // Matrix Mode
        glMatrixMode( GL_PROJECTION );

        // Matrix Load Identity
        glLoadIdentity();

        // Perspective
        gluPerspective(window.getSize().y/45.0, 1.0f*window.getSize().x/window.getSize().y, 0.0f, 100.0f);

        // Clear color buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Set Matrix Mode
        glMatrixMode( GL_MODELVIEW );

        // Matrix Load Identity
        glLoadIdentity();

        // Change camera position
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
            eyey -= 0.1f;
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
            eyey += 0.1f;
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
            eyex -= 0.1f;
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
            eyex += 0.1f;

        printf("%f %f\n", eyex, eyey);

        // Set the camera
        gluLookAt( eyex, -eyey, eyez, eyex, -eyey, 0, 0, 1, 0 );

        // RECTANGLE
        /*
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, Texture);
        glColor4f( 0.0, 1.0, 0.0, 1.0f );
        glScalef(1,-1,1);
        glBegin(GL_QUADS);
            glTexCoord2f(0.0f, 0.0f); glVertex3f(100, 200, 0.0f);
            glTexCoord2f(3.333333f, 0.0f); glVertex3f(200, 200, 0.0f);
            glTexCoord2f(3.333333f, 3.333333f); glVertex3f(200, 300, 0.0f);
            glTexCoord2f(0.0f, 3.333333f); glVertex3f(100, 300, 0.0f);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        */

        // Set color drawing
        glColor3f( 0.0, 0.0, 0.0 );
        glScalef(1,-1,1);

        // Draw cube
        drawCube(0.0f, 0.0f, 1000.0f, 100.0f, 100.0f, Texture);

        // Flush the scene
        glFlush();

        // Update the window
        window.display();
    }
    return 0;
}

void drawCube (float x, float y, float z, float width, float height, GLuint Texture)
{
    width /= 2;
    height /= 2;
    x += width;
    y += height;
    y = -y;
    width = -width;

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, Texture);
    glBegin(GL_QUADS);
        glColor3f(1.0f, 0.0f, 0.0f);
      // Top face
      glVertex3f( x + width, y + height, 0.0f);
      glVertex3f( x - width, y + height, 0.0f);
      glVertex3f( x - width, y + height, z);
      glVertex3f( x + width, y + height, z);

        glColor3f(1.0f, 1.0f, 0.0f);
      // Left face
      glVertex3f( x - width, y + height, z);
      glVertex3f( x - width, y + height, 0.0f);
      glVertex3f( x - width, y - height, 0.0f);
      glVertex3f( x - width, y - height, z);

        glColor3f(0.0f, 1.0f, 1.0f);
      // Right face
      glVertex3f( x + width, y + height, 0.0f);
      glVertex3f( x + width, y + height, z);
      glVertex3f( x + width, y - height, z);
      glVertex3f( x + width, y - height, 0.0f);

        glColor3f(0.0f, 0.0f, 0.0f);
      // Bottom face
      glVertex3f( x + width, y - height, 0.0f);
      glVertex3f( x - width, y - height, 0.0f);
      glVertex3f( x - width, y - height, z);
      glVertex3f( x + width, y - height, z);

      glColor3f(0.0f, 1.0f, 0.0f);
      // Front face
      glVertex3f( x + width, y + height, z);
      glVertex3f( x - width, y + height, z);
      glVertex3f( x - width, y - height, z);
      glVertex3f( x + width, y - height, z);
   glEnd();
   glDisable(GL_TEXTURE_2D);
}

This is my result:

Was it helpful?

Solution

You are correct, this problem is related to Z-Buffering.

There are actually two issues I see in your code:

  1. 32-bit depth buffers are not supported by all hardware

    • 24-bit Depth + 8-Bit Stencil is a much more compatible format, and more than adequate for your simple application. This can be requested using sf::ContextSettings (24, 8).

  2. Depth testing is disabled by default in OpenGL

    • Even if your hardware supports a 32-bit depth buffer, allocating the depth buffer alone is insufficient. You must enable it yourself by adding a call to glEnable (GL_DEPTH_TEST) after you create your sf::RenderWindow.

UPDATE:

I totally missed this the first time I ran through your code:

// Perspective
gluPerspective(
  window.getSize().y/45.0, 1.0f*window.getSize().x/window.getSize().y,
    0.0f, 100.0f);
    ~~~~

You are using 0.0 for the near plane in your perspective projection matrix. This is a very bad thing to do, it will completely mess up your depth range and this likely accounts for both of the screenshots you included in your comments.

Both planes must be positive values. If gluPerspective (...) were actually a part of the OpenGL API, it would generate a GL_INVALID_VALUE error under these circumstances. Also be aware that the distance between your near and far plane will determine the overall precision of your depth buffer (this is discussed in the documentation for gluPerspective).

To correct this, use a value that is very close to, but not exactly 0.0 for the near plane (i.e. 0.1).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top