Уроки по OpenGL с сайта OGLDev


Урок 01 - Создание окна

OpenGL не имеет собственного API для создания и управления окном. Современные оконные системы, которые поддерживают OpenGL, включают подсистему, обеспечивающую связь между контентом OpenGL и оконной системой. В системе X Window этот интерфейс называется GLX. Компания Microsoft предлагает WGL (произносится как Wiggle) для Windows и MacOS имеет CGL. Работа непосредственно с этими интерфейсами для создания окна, в котором будет отображаться графика, достаточна сложна, поэтому мы будем использовать высокоуровневые библиотеки дабы не ввязывать в детали. Мы будем использовать библиотеку, называемую 'OpenGL utility library', или сокращенно GLUT. Она предоставляет простейший API для управления оконной системой, а так же обработка событий, контроль ввода/вывода и ещё несколько других возможностей. К тому же GLUT кросс-платформенный, что значительно упрощает перенос под разные ОС. Хорошими альтернативами GLUT'y являются SDL и GLFW.

Прямиком к коду!

glutInit(&argc, argv);

Здесь мы инициализируем GLUT. Параметры могут быть переданы прямо из командной строки и включают полезные опции, например '-sync' включает синхронизацию у X, а и '-gldebug' автоматически проверяет на ошибки и выводит их.

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

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

glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("Tutorial 01");

Эти функции задают параметры окна и создают его. Так же мы даем ему заголовок.

glutDisplayFunc(RenderSceneCB);

Так как мы начали работать в оконной системе, большая часть действий с запущенной программой происходит через функции обратного вызова. GLUT берёт на себя взаимодействие с оконной системой и предоставляет нам несколько вариантов обратного вызова. Пока что мы используем только один, самый главный, который отрисовывает 1 кадр. Эта функция регулярно вызывается GLUT'ом.

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

Это наша первая встреча с понятием состояние OpenGL. Идея состояний в том, что они слишком сложны для того, что бы рассматриваться как вызов функции, принимающей несколько параметров (к тому же, правильно спроектированная функция не должна принимать много параметров). Вы должны указать шейдеры, буферы и прочие параметры, влияющие на рендеринг. В дополнение, вы будете часто хотеть сохранить некоторые эффекты в разных частях рендеринга (например, если вы никогда не будете выключать проверку глубины(depth test), то нет никакого смысла в включении её для каждого вызова рендера). Вот почему большинство конфигураций задаётся назначением флагов и переменных состояния OpenGL и рендеринг вызывается с ограниченным количеством параметров, проходит через вершины для отрисовки и их смещение. После вызова функции, изменяющей состояния, эта конкретная конфигурация остаётся не изменой до следующего вызова этой же функции с другим значением. Вызов выше устанавливает цвет, который будет использован во время очистки буфера кадра (объяснения будут позже). Цвет имеет 4 канала (красный, зелёный, синий, альфа-канал) и принимает значения от 0.0 и до 1.0.

glutMainLoop();

Этот вызов передаёт контроль GLUT'у, который теперь начнёт свой собственный цикл. В этом цикле он ждёт событий от оконной системы и передаёт их через функции обратного вызова, которые мы задали ранее. В нашем случае GLUT будет вызывать только функцию отображения на экран (RenderSceneCB), что бы дать ей возможность нарисовать кадр.

glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();

Всё что мы делаем в нашей функции рендера - это очистка буфера кадра (используя цвет, заданный выше, попробуйте изменить его). Вторая функция просит GLUT поменять фоновый буфер и буфер кадра местами. В следующем вызове рендер будет происходить в текущий буфер кадра, а фоновый буфер будет отображается.

powered byDisqus