Как правильно отобразить сферу в openGL

Я не очень хорошо разбираюсь в openGL/glut, но я успешно использовал его раньше для некоторых чрезвычайно простых вещей в 2D. Теперь я хочу иметь возможность рисовать сферы в 3D. Я пытаюсь смоделировать столкновения частиц, так что все, что мне действительно нужно сделать с точки зрения графики, это нарисовать сферы. Вот моя неудачная попытка

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

    glLoadIdentity();
            // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

    glutSwapBuffers();
}

void timerProc(int arg)
{
    glutTimerFunc(50,timerProc,0);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);

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

    glColor3f(0.0,0.0,0.0);  //color = black
    glPushMatrix();
        glTranslated(0,0,0);
        glutSolidSphere(.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    srand(time(NULL));
    init();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50,30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)-80,glutGet(GLUT_SCREEN_HEIGHT)-60);

    mainWindow=glutCreateWindow("New Window"); //global variable

    WIDTH=glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT=glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);

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

    glutTimerFunc(50,timerProc,0);
    glutMainLoop();
    return 0;
}

Надеюсь, все мои проблемы связаны с одной действительно основной ошибкой... По какой-то причине это создает овал. И, хотя овал довольно большой (может быть, около 1/8 экрана в ширину и высоту), если я уменьшу радиус до 0,73, он исчезнет, ​​я думаю, потому что он слишком мал, чтобы его увидеть. Как мне сделать так, чтобы эта сфера выглядела круглой, как вы ожидаете, и чтобы я мог видеть все, что происходит в заданном объеме, скажем, в коробке 10x10x10, как если бы вы просто стояли рядом с ящик с частицами, которые летали вокруг и вглядывались в него, или разумное приближение. Сейчас трудно сказать, на что именно я смотрю (я знаю, что стою в точке 1,1,1 и смотрю на начало координат, но трудно понять, что именно я вижу). Кроме того, иногда, когда я запустить его весь экран просто черный. Затем, когда я очищаю, строю и запускаю снова, все в порядке. Не очень большая проблема, но раздражает, и я хотел бы понять, что происходит. Кроме того, когда количество срезов и стеков было меньше, все выглядело бы хорошо, если бы радиус был большим, но сильно искажался бы, когда радиус был маленьким, что мне показалось очень странным...


person WanderingMathematician    schedule 15.04.2014    source источник
comment
Не уверен, что это основная причина вашей проблемы, но я бы начал с перемещения всего вашего кода рисования сферы из вашего timerProc в renderscene(), и чтобы ваш таймер просто вызывал glutPostRedisplay() вместо того, чтобы делать свой собственный рисунок. Вероятно, это не решит вашу проблему полностью, но это хорошая практика. По крайней мере, это обеспечит очистку буферов цвета и глубины в каждом кадре. Кроме того, добавьте вызов glFlush() перед заменой буферов. Это обеспечит завершение всех вызовов рисования.   -  person redsoxfantom    schedule 16.04.2014
comment
Сфера по-прежнему исчезает, если вы используете glutSolidSphere(0.73, 10, 10) (т.е. имеете меньше фрагментов/стеков)?   -  person Christian Aichinger    schedule 16.04.2014
comment
@redsoxfantom Изменил это, хорошо, что есть хорошая практика :) Но это ничего не изменило. @ChristianAichinger Да, да, это так. Если я оставлю радиус больше: glutSolidSphere(0.74, 10, 10) он ужасно деформируется и станет намного меньше.   -  person WanderingMathematician    schedule 16.04.2014


Ответы (1)


Основная проблема, с которой вы сталкиваетесь, - это отсечение по оси Z. Начальный диапазон Z для сцены равен (-1, 1), поэтому вы видите только часть фактической сферы, и, изменяя ее размер, вы выходите за пределы диапазона Z.

Изображение

Я вижу несколько проблем в коде. Хорошо бы понять, как на самом деле работает рабочий процесс GLUT.

Давайте посмотрим, что код делает неправильно.

Основной

int main(int argc, char **argv)
{
    srand(time(NULL));
    init();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH) - 80, 
                       glutGet(GLUT_SCREEN_HEIGHT) - 60);

    mainWindow = glutCreateWindow("New Window"); //global variable

    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);

Здесь вы определяете функцию отображения. Он вызывается каждый раз, когда содержимое окна должно быть аннулировано. В этом случае он становится недействительным только при запуске. Функция renderScene ничего удивительного не делает, просто очищает экран. Таким образом, вы получаете черный экран в начале.

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

На данный момент нет необходимости смешивать. Вы можете вообще пропустить эту часть.

    glutTimerFunc(50, timerProc, 0);

Теперь вы настроили функцию timerProc для вызова через 50 миллисекунд.

    glutMainLoop();

Как указано в документации: glutMainLoop входит в цикл обработки событий GLUT. Эта подпрограмма должна вызываться не более одного раза в программе GLUT. После вызова эта подпрограмма никогда не вернется. При необходимости он будет вызывать любые зарегистрированные обратные вызовы.

    return 0;
}

Рендер сцены

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

Это единственное место, где вы очищаете экран. Timer Func этого не делает.

    glLoadIdentity();

Вы сбрасываете матрицы.

    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);

Настройка матриц. (одна матрица, если быть точным)

    glutSwapBuffers();

И ничего не рисуя, вы меняете местами буферы.

}

Функция рендеринга сцены вызывается каждый раз, когда нужно перерисовать рамку окна.

Таймер

Эта функция полагается на то, что экран сначала очищается с помощью renderScene. void timerProc (int arg) { glutTimerFunc (50, timerProc, 0);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);

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

На этот раз не очистить. Только настройка цвета.

    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

Как это исправить?

Просто настройте матрицы. С правильным диапазоном Z.

void resetTransformations() {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1, 1, -1, 1, -1000, 1000);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1.0f, 1.0f, 1.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f);
}

void renderScene()
{
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    resetTransformations();

    // Just to see some triangles
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glColor3f(0.0, 0.0, 0.0);  //color = black
    glPushMatrix();
    glTranslated(0, 0, 0);
    glutSolidSphere(0.74, 500, 500);
    glPopMatrix();

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    srand(time(NULL));

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(50, 30);
    glutInitWindowSize(256, 256);

    mainWindow = glutCreateWindow("New Window"); //global variable

    WIDTH = glutGet(GLUT_WINDOW_WIDTH); //global variable
    HEIGHT = glutGet(GLUT_WINDOW_HEIGHT); //global variable

    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);

    glutMainLoop();
    return 0;
}
person mrVoid    schedule 15.04.2014
comment
Это работает, но все еще происходит несколько странных вещей. Насколько я понимаю, glOrtho настроено, как далеко вы можете видеть объекты? Если я изменю этот вызов на glOrtho(-10, 10, -10, 10, -1000, 1000);, а радиус на что-то большее, скажем, 7, сфера сожмется, когда я запущу код. Почему он сжимается? Я думал, что ничего не меняется, и код рисования даже вызывается только один раз, так как содержимое окна становится недействительным только при запуске программы... - person WanderingMathematician; 16.04.2014
comment
glOrtho — это параллельная проекция определенного блока пространства. Если вы увеличите ширину и высоту блока, как glOrtho(-10, 10, -10, 10, -1000, 1000);, ваша сфера будет занимать меньше места в этом блоке. - person mrVoid; 17.04.2014
comment
Я имел в виду, что он сжимается во время работы программы. Сначала он меньше, чем раньше, что имеет смысл, а затем сжимается до нуля во время выполнения. - person WanderingMathematician; 17.04.2014
comment
Правда, в ответе ошибка. Идентификация не установлена. Фиксированный. - person mrVoid; 17.04.2014