Знакомимся с OpenGL

OpenGL


Знакомство с OpenGL нужно начать с того, что OpenGL — это спецификация. Т.е. OpenGL лишь определяет набор обязательных возможностей. Реализация же зависит от конкретной платформы.
OpenGL является кроссплатформенным, независимым от языка программирования API для работы с графикой. OpenGL — низкоуровневый API, поэтому для работы с ним неплохо иметь некоторое представление о графике в целом и знать основы линейной алгебры.

Именования


Скажем пару слов об именовании функций в OpenGL. Во-первых имена всех функций, предоставляемых непосредственно OpenGL, начинаются с приставки gl. Во-вторых функции, задающие некоторый параметр, характеризующийся набором чисел (например координату или цвет), имеют суффикс вида [число параметров + тип параметров + представление параметров].
  • Число параметров — указывает число принимаемых параметров. Принимает следующие значения: 1, 2, 3, 4
  • Тип параметров — указывает тип принимаемых параметров. Возможны следующие значения: b, s, i, f, d, ub, us, ui. Т.е. byte (char в C, 8-битное целое число), short (16-битное целое число), int (32-битное целое число), float (число с плавающей запятой), double (число с плавающей запятой двойной точности), unsigned byte, unsigned short, unsigned int (последние три — беззнаковые целые числа)
  • Представление параметров — указывает в каком виде передаются параметры, если каждое число по отдельности, то ничего не пишется, если же параметры передаются в виде массива, то к названию функции дописывается буква v

Пример: glVertex3iv задает координату вершины, состоящую из трех целых чисел, передаваемых в виде указателя на массив.

Графика


Все графические объекты в OpenGL представляют собой набор точек, линий и многоугольников. Существует 10 различных примитивов, при помощи которых строятся все объекты. Как двухмерные, так и трехмерные. Все примитивы в свою очередь задаются точками — вершинами.
  • GL_POINTS — каждая вершина задает точку
  • GL_LINES — каждая отдельная пара вершин задает линию
  • GL_LINE_STRIP — каждая пара вершин задает линию (т.е. конец предыдущей линии является началом следующей)
  • GL_LINE_LOOP — аналогично предыдущему за исключением того, что последняя вершина соединяется с первой и получается замкнутая фигура
  • GL_TRIANGLES — каждая отдельная тройка вершин задает треугольник
  • GL_TRIANGLE_STRIP — каждая следующая вершина задает треугольник вместе с двумя предыдущими (получается лента из треугольников)
  • GL_TRIANGLE_FAN — каждый треугольник задается первой вершиной и последующими парами (т.е. треугольники строятся вокруг первой вершины, образуя нечто похожее на диафрагму)
  • GL_QUADS — каждые четыре вершины образуют четырехугольник
  • GL_QUAD_STRIP — каждая следующая пара вершин образует четырехугольник вместе с парой предыдущих
  • GL_POLYGON — задает многоугольник с количеством углов равным количеству заданных вершин

Для задания примитива используется конструкция glBegin (тип_примитива)…glEnd (). Вершины задаются glVertex*. Вершины задаются против часовой стрелки. Координаты задаются от верхнего левого угла окна. Цвет вершины задается командой glColor*. Цвет задается в виде RGB или RGBA. Команда glColor* действует на все вершины, что идут после до тех пор, пока не встретится другая команда glColor* или же на все, если других команд glColor* нет.
Вот код рисующий квадрат с разноцветными вершинами:
  1. glBegin(GL_QUADS);
  2. glColor3f(1.0, 1.0, 1.0);
  3. glVertex2i(250, 450);
  4. glColor3f(0.0, 0.0, 1.0);
  5. glVertex2i(250, 150);
  6. glColor3f(0.0, 1.0, 0.0);
  7. glVertex2i(550, 150);
  8. glColor3f(1.0, 0.0, 0.0);
  9. glVertex2i(550, 450);
  10. glEnd();


Основы программы на OpenGL


Для платформонезависимой работы с окнами можно использовать библиотеку GLUT. GLUT упрощает работу с OpenGL.
Для инициализации GLUT в начале программы надо вызвать glutInit (&argc, argv). Для задания режима дисплея вызывается glutInitDisplayMode (режим), где режим может принимать следующие значения:
  • GLUT_RGBA — включает четырехкомпонентный цвет (используется по умолчанию)
  • GLUT_RGB — то же, что и GLUT_RGBA
  • GLUT_INDEX — включает индексированный цвет
  • GLUT_DOUBLE — включает двойной экранный буфер
  • GLUT_SINGLE — включает одиночный экранный буфер (по умолчанию)
  • GLUT_DEPTH — включает Z-буфер (буфер глубины)
  • GLUT_STENCIL — включает трафаретный буфер
  • GLUT_ACCUM — включает буфер накопления
  • GLUT_ALPHA — включает альфа-смешивание (прозрачность)
  • GLUT_MULTISAMPLE — включает мультисемплинг (сглаживание)
  • GLUT_STEREO — включает стерео-изображение

Для выбора нескольких режимов одновременно нужно использовать побитовое ИЛИ '|'. Например: glutInitDisplayMode (GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH) включает двойную буферизацию, Z-буфер и четырехкомпонентный цвет. Размеры окна задаются glutInitWindowSize (ширина, высота). Его позиция — glutInitWindowPosition (х, у). Создается окно функцией glutCreateWindow (заголовок_окна).
GLUT реализует событийно-управляемый механизм. Т.е. есть главный цикл, который запускается после инициализации, и в нем уже обрабатываются все объявленные события. Например нажатие клавиши на клавиатуре или движение курсора мыши и т.д. Зарегистрировать функции-обработчики событий можно при помощи следующих команд:
  • void glutDisplayFunc (void (*func) (void)) — задает функцию рисования изображения
  • void glutReshapeFunc (void (*func) (int width, int height)) — задает функцию обработки изменения размеров окна
  • void glutVisibilityFunc (void (*func)(int state)) — задает функцию обработки изменения состояния видимости окна
  • void glutKeyboardFunc (void (*func)(unsigned char key, int x, int y)) — задает функцию обработки нажатия клавиш клавиатуры (только тех, что генерируют ascii-символы)
  • void glutSpecialFunc (void (*func)(int key, int x, int y)) — задает функцию обработки нажатия клавиш клавиатуры (тех, что не генерируют ascii-символы)
  • void glutIdleFunc (void (*func) (void)) — задает функцию, вызываемую при отсутствии других событий
  • void glutMouseFunc (void (*func) (int button, int state, int x, int y)) — задает функцию, обрабатывающую команды мыши
  • void glutMotionFunc (void (*func)(int x, int y)) — задает функцию, обрабатывающую движение курсора мыши, когда зажата какая-либо кнопка мыши
  • void glutPassiveMotionFunc (void (*func)(int x, int y)) — задает функцию, обрабатывающую движение курсора мыши, когда не зажато ни одной кнопки мыши
  • void glutEntryFunc (void (*func)(int state)) — задает функцию, обрабатывающую движение курсора за пределы окна и его возвращение
  • void glutTimerFunc (unsigned int msecs, void (*func)(int value), value) — задает функцию, вызываемую по таймеру

Затем можно запускать главный цикл glutMainLoop ().

Первая программа


Теперь мы знаем основы работы с OpenGL. Можно написать простую программу для закрепления знаний.
Начнем с того, что нужно подключить заголовочный файл GLUT:
  1. #if defined(linux) || defined(_WIN32)
  2. #include <GL/glut.h>    /*Для Linux и Windows*/
  3. #else
  4. #include <GLUT/GLUT.h>  /*Для Mac OS*/
  5. #endif

Теперь мы уже знаем, что писать в main. Зарегистрируем два обработчика: для рисования содержимого окна и обработки изменения его размеров. Эти два обработчика по сути используются в любой программе, использующей OpenGL и GLUT.
  1. int main (int argc, char * argv[])
  2. {
  3.         glutInit(&argc, argv);
  4.         glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); /*Включаем двойную буферизацию и четырехкомпонентный цвет*/
  5.        
  6.         glutInitWindowSize(800, 600);
  7.         glutCreateWindow(«OpenGL lesson 1»);
  8.        
  9.         glutReshapeFunc(reshape);
  10.         glutDisplayFunc(display);
  11.        
  12.         glutMainLoop();
  13.  
  14.         return 0;
  15. }

Теперь надо написать функцию-обработчик изменений размеров окна. Зададим область вывода изображения размером со все окно при помощи команды glViewport (х, у, ширина, высота). Затем загрузим матрицу проекции glMatrixMode (GL_PROJECTION), заменим ее единичной glLoadIdentity () и установим ортогональную проекцию. И наконец загрузим модельно-видовую матрицу glMatrixMode (GL_MODELVIEW) и заменим ее единичной.
В итоге получим:
  1. void reshape(int w, int h)
  2. {
  3.         glViewport(0, 0, w, h);
  4.        
  5.         glMatrixMode(GL_PROJECTION);
  6.         glLoadIdentity();
  7.         gluOrtho2D(0, w, 0, h);
  8.        
  9.         glMatrixMode(GL_MODELVIEW);
  10.         glLoadIdentity();
  11. }

Осталось только написать функцию рисования содержимого окна. Рисовать будем тот квадрат, что я приводил выше в качестве примера. Добавить придется совсем немного кода. Во-первых перед рисованием надо очистить различные буфера при помощи glClear (режим). Используется также как и glutInitDisplayMode. Возможные значения:
  • GL_COLOR_BUFFER_BIT — для очистки буфера цвета
  • GL_DEPTH_BUFFER_BIT — для очистки буфера глубины
  • GL_ACCUM_BUFFER_BIT — для очистки буфера накопления
  • GL_STENCIL_BUFFER_BIT — для очистки трафаретного буфера

В нашем случае нужно очистить только буфер цвета, т.к. другие мы не используем. Во-вторых после рисования нужно попросить OpenGL сменить экранные буфера при помощи glutSwapBuffers (), ведь у нас включена двойная буферизация. Все рисуется на скрытом от пользователя буфере и затем происходит смена буферов. Делается это для получения плавной анимации и для того, чтобы не было эффекта мерцания экрана.
Получаем:
  1. void display()
  2. {
  3.         glClear(GL_COLOR_BUFFER_BIT);
  4.        
  5.         glBegin(GL_QUADS);
  6.         glColor3f(1.0, 1.0, 1.0);
  7.         glVertex2i(250, 450);
  8.         glColor3f(0.0, 0.0, 1.0);
  9.         glVertex2i(250, 150);
  10.         glColor3f(0.0, 1.0, 0.0);
  11.         glVertex2i(550, 150);
  12.         glColor3f(1.0, 0.0, 0.0);
  13.         glVertex2i(550, 450);
  14.         glEnd();
  15.        
  16.         glutSwapBuffers();
  17. }


Итог


Все! Можно компилировать. Должно получиться что-то вроде этого:
screen
Весь код целиком (для кто не осилил статью).
В принципе ничего сложного в этом нет, по крайней мере если вы уже сталкивались с графикой до этого.

OpenGL — удобный инструмент для создания кроссплатформенных приложений, использующий графику. OpenGL легко использовать с тем языком программирования, который вам более удобен. Привязки к OpenGL есть для множества популярных языков, таких как C, C++, C#, Java, Python, Perl, VB и других. Посмотреть информацию о них можно на официальном сайте OpenGL.
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 47
  • +7
    А продолжение будет?
    • +4
      Постараюсь написать
      • +1
        Думаю многие будут благодарны.

        Начало уже ушло в закладки, ждём продолжения.
    • +12
      Для интересующихся советую взглянуть на туториалы NeHe: nehe.gamedev.net/
      • +8
        Тогда уж сразу ссылка на перевод: pmg.org.ru/nehe/index.html
        Очень полезные материалы.
        • +1
          Перевод достаточно кривой. Знающим английский лучше читать оригинал.
        • +2
          NeHe конечно вечен, но glBegin/glEnd к сожалению уже deprecated-функционал. Настоятельно рекомендую code.google.com/p/gl33lessons/ для начала.
          • 0
            Спасибо за ссылку. Надо будет почитать.
            • 0
              Не могли бы вы еще литературки подкинуть? Будет чем после сессии заняться.
          • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Возможно. Взял в качестве примера первое, что пришло в голову.
            • 0
              Отличная шпаргалка для начинающих. Спасибо!
              • +8
                Я тоже начинал с glBegin, glEnd, glVertex.
                Когда мне понадобилось написать первое OpenGL приложение для Android, я обнаружил, что в OpenGL ES уже нет ни glBegin ни glEnd ни glVertex, оно и к лучшему =)

                Так что лучше сразу думать в терминах glDrawArrays, glDrawElements итд.
                • 0
                  Но зато в OpenGL ES остался стандартный шейдерный конвейер, если не ошибаюсь.
                • +16
                  Статья актуальна для старых версий OpenGL. Уже начиная с версии 1.5 отрисовку геометрии настоятельно рекомендуется реализовывать с использованием вершинных буферов (сегодня актуальна версия 4.1). Про функции фиксированного конвейера обработки изображений (типа glMatrixMode) во времена программируемого конвейера (со времен GeForce 3) говорить тоже не стоит. Если честно, то данный «Hello world» устарел лет так на 7-8.
                  • +9
                    напишите пожалуйста мануал для современного opengl
                    • 0
                      К сожалению OpenGL не использую более 3 лет, так как наелся бесконечными багофичами и кривой поддержкой со стороны производителей железа. Молчу про то, что для элементарных действий, к примеру рендер шрифтов, надо привязываться к 10ку других библиотек, на согласование стиля кодирования и написания дополнительных слоев в проекте уходит чрезмерно много времени, как следствие — снижение профита.
                      • 0
                        Часто встречаю подобные коменты в сторону OpenGL и хочу спросить, ради самообразования, нет ли у вас ссылочки на материалы либо своими словами о том, как эти проблемы обходятся? Исходя из того, что OpenGL кроссплатформенный хотелось бы его поюзать, да и опыт всяких кармаков не даёт покоя, потому если есть какие полезные материалы по теме подводных камней был бы признателен.
                        • 0
                          Все зависит от решаемой задачи. Если вы не создаете свой движок, то лучше воспользоваться готовыми объектно-ориентированными лейерами, так написание своих библиотек по обработки матриц, векторов и другой математики — это чистый велосипед. Для своего движка (если вы Кармак и у вас много времени или денег) конечно все придется делать все самому.
                          Но ряд проблем в виде странного поведения OpenGL на недорогом оборудовании (в основном не самых дорогих видеокарт ATI и Intel) с которыми приходилось сталкиваться, вообще не имеют решений, служба поддержки лишь отправляет на скачивание новых драйверов. Особенно это касается шейдерных техник, поведение даже элементарных программ может разница у каждого вендора. Хотя про GLSL — это уже другой разговор )
                  • 0
                    Про CSG на OpenGL будет? Там какая-то замороченная работа с трафаретом
                    • 0
                      Я лично про CSG на OpenGL ничего рассказать не могу. Может кто другой поделится знаниями.
                      • Вообще-то, всё это уже больше 10 лет в интернете лежит, гугл в помощь.
                      • +5
                        извините, но от брюзжаиня удержаться сложно.
                        формулировка «против часовой стрелки» — абсолютно бессмысленная и беспощадная,
                        без упоминания нормали или хотябы «видимой стороны».
                        • +21
                          Очередной туториал про OpenGL образца девяностых не нужен, как и ссылки на nehe. Более-менее актуальный туториал duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html.
                          • 0
                            Этот топик пригодился бы на второй лабе по компьютерной графике, на втором курсе… Вы даже не представляете как бы он пригодился… :)
                            • 0
                              году эдак в 2000-м…
                              • 0
                                Зря иронизируете. Нас этому учили в этом году.
                            • 0
                              Спасибо, именно то, что я искал — просто и наглядно о самых основах.
                              • +2
                                имхо лучше без glut-а тоже рассказать, не везде он есть, к примеру OpenGL ES )
                                • –1
                                  21 век блин… и синтаксис процедурный…
                                  Я конечно понимаю, что создан он в бородатые годы еще, но это же все-равно печально…
                                  • –1
                                    Чем плох процедурный синтаксис? Или Вы под влиянием ООП статей так написали?
                                    • 0
                                      Конечно, под влиянием статей — как же приятно соглашаться с большинством. От процедурного синтаксиса у меня начинает расти борода и свитер.

                                      А если серьезно, то, по моим субъективным ощущениям, сочетание плюсового ооп с процедурами гл вызывает подсознательно какой-то дискомфорт, хочется создавать объекты. Любая библиотека должна естественно вписываться в язык.
                                  • +1
                                    Это все уже устарело, glBegin() / glEnd() уже не используются в 3ей версии, оно deprecated. Лучше уже сразу изучать современный OpenGL 3 и 4 версий. Неплохой учебник на русском.
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                      • 0
                                        Выше уже неоднократно написали о том, что материал не слишком актуален. Если делать крутые приложение с трехмерной графикой, то конечно лучше использовать самые последние версии OpenGL. Но для расширения кругозора думаю и старый OpenGL интересен. Тем более в графике я и сам практически новичок.
                                        • 0
                                          Может стоит начинать с основ для новичков? Старый OpenGL для этого как раз лучше всего подходит. А в дальнейшем можно будет рассмореть и современные спецификации и рекомендации к написанию кода. Хабрачитатель от этого получит более легкое понимание материала (от простого к сложному) и параллель развития OpenGL. Не так ли?
                                          • 0
                                            Основы это основы компьютерной графики, а не как работать с определённым апи. Мне понравилась «Интерактивная компьютерная графика» Эйнджела, там хоть всё тот же устаревший fixed pipeline но полностью объясняется как он работает. По книге я смог написать простенький софтварный рендер — очень полезный опыт.
                                            • 0
                                              Видимо я не совсем корректно выразился. Под основами я имел ввиду основы работы с данным фреймворком.
                                        • 0
                                          Для интересующихся — еще две ссылочки на OpenGL RedBook и примеры к этой книге. Но одна маленькая проблема — актуально для версии OpenGL 1.1
                                          fly.cc.fer.hr/~unreal/theredbook/
                                          www.opengl.org/resources/code/samples/redbook/
                                          • 0
                                            Я конечно понимаю, что статья рассчитывалась на начинающих, но в ней ничего не сказано про системы координат и матрицу трансформации — самую-самую основу, без понимания которой пытаться что-то рисовать — занятие тупиковое. Попробуйте новичку объяснить, что такое модельно-видовая матрица, и как в OpenGL разграничивать перемещение камеры и перемещение сцены.
                                            • +3
                                              Сколько мне не попадалось туториалов для новичков в OpenGL, всегда почему-то они заканчиваются примером бесполезного разноцветного полигона…
                                              • 0
                                                А что вам хотелось бы увидеть полезного в туториале для новичков?
                                                • +1
                                                  Я очень плохо знаком как с OpenGL, так и с DirectX (хотя кое-что простое писал, но больше занимался software mode графикой). Поэтому в туториале для новичков хотелось бы увидеть побольше примеров и теории про текстуры, загрузку объектов из файлов, возможностями для работы с камерой и вообще всё то, что больше приближено к реальности, к тому, что можно увидеть в настоящих играх. Также, очень интересуют возможности использования OpenGL для 2D ренденга, т.е. для реализации «игрового меню» к примеру, или плоских 2D бродилок с 3D эффектами. Вот это очень хотелось бы увидеть :)
                                                  • 0
                                                    То, что вы написали по моему скромному мнению не подходит для стартовой статьи для новичков.
                                                    Про текстуры, загрузку моделей из файлов и работу с камерой попробую потом написать.
                                                    • +1
                                                      А вы сделайте статью не для новичков =) Проблема в том и заключается, что уроков, подобных этому, в интернете море, а по озвученным темам очень мало и/или почти нету и/или они устарели. Можно еще вспомнить про более специфические темы, такие как привязка к физическим движкам.
                                                      • 0
                                                        По поводу устаревания: то, что я могу написать тоже будет не слишком актуально, т.к. я работал только со старым OpenGL без всяких шейдеров и прочего.
                                              • +1
                                                Мои глаза! Опять deprecated :)

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