Что может привести к тому, что полигоны в OpenGL будут отображаться не по порядку?

Я пытаюсь получить некоторый практический опыт работы с OpenGL, поэтому я пишу несколько базовых программ. Приведенная ниже короткая программа — это моя первая попытка рендеринга сплошного объекта — вращающегося куба — но по какой-то причине некоторые задние многоугольники, кажется, рисуются поверх передних. У меня вопрос, что может быть причиной этого? Это как-то связано с буфером глубины? Я обнаружил, что в этом случае включение отсечения лиц скроет эффект, но зачем это нужно? Разве лицо, скрытое более близким лицом, не должно быть все равно скрыто?

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

typedef struct{
    int width;
    int height;
    char * title;
} window;
window win;

float theta = 0;
const float rotRate = 0.05;//complete rotations per second
int lastTime;

const float verts[][3] = {
    {0.0,0.0,0.0},
    {1.0,0.0,0.0},
    {0.0,1.0,0.0},
    {0.0,0.0,1.0},
    {0.0,1.0,1.0},
    {1.0,0.0,1.0},
    {1.0,1.0,0.0},
    {1.0,1.0,1.0}};

const int faceIndices[][4] = {
    {3,5,7,4},//front
    {1,0,2,6},//back
    {4,7,6,2},//top
    {0,1,5,3},//bottom
    {5,1,6,7},//right
    {0,3,4,2}};//left

void display(){
    //timing and rotation 
    int currentTime = glutGet(GLUT_ELAPSED_TIME);
    int dt = lastTime - currentTime;
    lastTime = currentTime;
    theta += (float)dt/1000.0*rotRate*360.0;
    if (theta > 360.0) theta += -360.0;

    //draw
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -5.0);
    glRotatef(theta, 0.0, 1.0, 0.0);
    glTranslatef(-1.0,-1.0,-1.0);
    glScalef(2.0, 2.0, 2.0);
    int f;
    for(f=0; f<6;f++){
        glBegin(GL_POLYGON);
        int v;
        for(v=0; v<4; v++){
            glColor3fv(verts[faceIndices[f][v]]);
            glVertex3fv(verts[faceIndices[f][v]]);
        }
        glEnd();
    }

    glutSwapBuffers();
}

void initializeGLUT(int * argc, char ** argv){
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowSize(win.width, win.height);
    glutCreateWindow("OpenGL Cube");
    glutDisplayFunc(display);
    glutIdleFunc(display);
}

void initializeGL(){
    //Setup Viewport matrix
    glViewport(0,0,win.width, win.height);

    //Setup Projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45,(float) win.width/win.height, 0.1, 100.0);

    //Initialize Modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //Other
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearDepth(1.0);
}

int main(int argc, char** argv){
    win.width = 640;
    win.height = 480;

    initializeGLUT(&argc, argv);
    initializeGL();

    glutMainLoop();

    return 0;
}

person AIGuy110    schedule 19.05.2014    source источник
comment
stackoverflow.com/a/18922286/2003898 Это может помочь вам понять проблему. Поскольку OpenGL различается между передней и задней сторонами модделей   -  person dhein    schedule 19.05.2014


Ответы (1)


Это как-то связано с буфером глубины?

Да, это проблема с буфером глубины, вы включили буфер глубины в своем коде, но, очевидно, вы потеряли некоторые шаги, чтобы использовать буфер глубины.

  1. Включите проверку глубины, вызвав glEnable(GL_DEPTH_TEST)
  2. Установите функцию проверки глубины с помощью glDepthFunc, GL_LEQUAL — рекомендуемый выбор для большинства случаев, glDepthFunc(GL_LEQUAL); значение по умолчанию — GL_LESS.
  3. Вызовите glClearDepth, чтобы установить очищенное значение, начальное значение 1,0, этот шаг не является обязательным, если вы хотите значение по умолчанию.
  4. Не забудьте очистить бит глубины перед рисованием, glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Я обнаружил, что в этом случае включение отсечения лиц скроет эффект, но зачем это нужно?

По умолчанию OpenGL не отбрасывает лица, рекомендуемый вариант

  1. Определите вершины в порядке по часовой стрелке как заднюю поверхность (это также выбор OpenGL)
  2. Отбрасывайте задние грани, когда это необходимо.

В вашем случае вы определили все вершины многоугольника в порядке против часовой стрелки, поэтому по умолчанию все они являются передними гранями, вам просто нужно отсечь задние грани, чтобы они не рисовались, поэтому следующий код также решает вашу проблему.

glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);

Разве лицо, скрытое более близким лицом, не должно быть все равно скрыто?

Да, это имеет смысл, поскольку мы люди, но для компьютера ваша обязанность сказать ему, как это сделать.

Использованная литература:

Буфер глубины

Выделение лица

person zdd    schedule 19.05.2014