Многоугольник внутри другого многоугольника в той же плоскости - PullRequest
1 голос
/ 13 июня 2011

В моем коде OpenGL странное поведение. Я хочу нарисовать ковер на земле.

В приведенном ниже коде, если GROUND_SIZE больше 2071, а CARPET_HEIGHT меньше 0,0003, меньший многоугольник рисоваться не будет. Порядок рисования не меняет получившегося изображения.

#include <GL/glut.h>

const int GROUND_SIZE = 3000;
const bool GROUND_FIRST = true;
const float CARPET_HEIGHT = 0.0003;

void carpet(){
    glColor3f(1.0,0.0,0.0);
    glBegin(GL_QUADS);
        glNormal3f(0,1,0);
        glVertex3f(-1.0, -1.0, CARPET_HEIGHT);
        glVertex3f( 1.0, -1.0, CARPET_HEIGHT);
        glVertex3f( 1.0,  1.0, CARPET_HEIGHT);
        glVertex3f(-1.0,  1.0, CARPET_HEIGHT);
    glEnd();
}
void ground(){
    glColor3f(0.0,0.7,0.0);
    glBegin(GL_QUADS);
        glNormal3f(0,1,0);
        glVertex3f(-GROUND_SIZE, -GROUND_SIZE, 0);
        glVertex3f( GROUND_SIZE, -GROUND_SIZE, 0);
        glVertex3f( GROUND_SIZE,  GROUND_SIZE, 0);
        glVertex3f(-GROUND_SIZE,  GROUND_SIZE, 0);
    glEnd();
}

void draw(){
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    if (GROUND_FIRST) {
        ground();
        carpet();
    }
    else {
        carpet();
        ground();
    }

    glutSwapBuffers();
}

int main(){

    int argc = 1; char* argv[] = { (char*)"" };
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowPosition(100, 50);
    glutInitWindowSize(640, 640);
    glutCreateWindow("Window");

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);

    glClearColor(0.0f, 1.0f, 1.0f, 1.0f);

    glutDisplayFunc(draw);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, 1, 0.1, 1000.0);
    gluLookAt(0.0, -5.0, 1.0,    0.0f, 0.0f, 1.0f,    0,0,1);

    glutMainLoop();
    return 0;
}

Я хочу понять правила, которые OpenGL использует, чтобы решить, будет ли он рисовать многоугольник внутри другого многоугольника в той же плоскости.

Спасибо

1 Ответ

4 голосов
/ 13 июня 2011

Во-первых, несколько ошибок в коде.

Никогда не помещайте матрицу gluLookAt в матрицу GL_PROJECTION.Это может играть havok с вашим освещением.Матрица gluLookAt должна быть первой матрицей, вставленной вами в GL_MODELVIEW.

Также неплохо иметь матрицу GL_MODELVIEW в качестве матрицы по умолчанию.То есть любой код, который переключается на GL_PROJECTION (или одну из матриц текстуры), отвечает за переключение обратно на GL_MODELVIEW сразу после того, как это сделано с другой матрицей.

Наконец, всегда полезно вызывать glClearDepth иglDepthFunc.Значения по умолчанию (1.0 и GL_LESS) - это именно то, что вы хотите, но всегда хорошо быть откровенным об этих вещах.Таким образом, вам не нужно искать в спецификации, чтобы убедиться, что значения по умолчанию соответствуют вашим ожиданиям.

Теперь перейдем к основной проблеме.

Правила дляэто всего лишь правила для буферов глубины.Что является простым и сложным одновременно.

Во-первых, есть наклон двух плоскостей.Хотя они, безусловно, имеют одинаковый наклон в мировом пространстве, они не обязательно имеют одинаковый наклон в пространстве после проецирования.Это связано с ошибками с плавающей точкой в ​​различных вычислениях, которые преобразуются из мирового пространства в пространство после проецирования.

Во-вторых, если Z-разница между ними слишком мала, то может произойти то, что они будутполучить то же значение Z, примененное к ним.Или ковер может даже иметь меньшее значение Z из-за ошибок с плавающей точкой.

Я полагаю, если бы вы анимировали угол обзора, вы бы увидели, что ковровое покрытие появляется и выходит из поля зрения.

Одна простая вещь, которую вы можете сделать, это всегда рисовать ковер после плоскости земли и использовать GL_LEQUAL для glDepthFunc.Это может не работать 100% времени, опять же из-за ошибок с плавающей точкой.

Следующим шагом является использование смещения полигонов.Это смещает значение Z примитива на некоторое фиксированное значение.Детали того, как это работает, слишком технически для этого обсуждения (проверьте спецификацию OpenGL, если вам интересно), но основная идея заключается в том, что ваша carpet функция должна выглядеть примерно так:

glEnable(GL_POLYGON_OFFSET_FILL); //Activates polygon offsets for filled triangles.
glPolygonOffset(0, 2); //The 2 is just for safety's sake; 1 ought to be enough.
//Draw the carpet
glDisable(GL_POLYGON_OFFSET_FILL); //Turn off polygon offsetting.
...