Opengl руководство по программированию библиотека программиста. Знакомимся с OpenGL

3.2.3 Видовые трансформации
Видовое преобразование изменяет позицию и ориентацию точки обзора. Если вы вспомните аналогию с камерой, видовое преобразование устанавливает треногу для камеры и направляет камеру на модель. Видовое преобразование аналогично передвижению и поворотам камеры также обычно состоит из переносов и поворотов.
Помните также, что для достижения определенной композиции в результирующем изображении или фотографии вы можете либо перемещать камеру, либо перемещать все объекты сцены в противоположном направлении. Таким образом, модельное преобразование, поворачивающее объекты сцены против часовой стрелки аналогично видовому преобразованию, которое поворачивает камеру по часовой стрелке. И, наконец, имейте в виду, что команды видового преобразования должны вызываться перед всеми командами модельных преобразований, чтобы модельные преобразования были применены к объектам первыми.
Вы можете производить видовые преобразования любым из нескольких способов, описанных далее. Вы также можете использовать расположение и ориентацию точки обзора по умолчанию, то есть ее расположение в начале координат и направление просмотра вдоль отрицательного направления оси z .

Используйте одну или несколько команд модельных преобразований
(glTranslate*() или glRotate*() ). Вы можете думать об эффекте этих

преобразований как перемещении камеры, или как о перемещении всех объектов сцены относительно стационарной камеры.

Используйте команду библиотеки утилит gluLookAt() для определения точки и направления обзора. Эта команда инкапсулирует в себе серию поворотов и переносов.

Создайте свою собственную (пользовательскую) функцию, инкапсулирующую повороты и переносы. В некоторых приложениях такая функция может понадобиться для того, чтобы можно было задавать видовую трансформацию каким-либо специфическим путем. Например, вам может понадобиться задавать преобразование в терминах полярных координат для камеры, вращающейся вокруг объекта или в терминах углов наклона самолета в полете.
3.2.3.1 Использование glTranslate*() и glRotate*()
Когда вы используете команды модельных преобразований для эмуляции видовых, вы пытаете передвинуть точку наблюдения в желаемом направлении, сохранив объекты неподвижными. Поскольку точка наблюдения изначально находится в начала координат, и поскольку объекты обычно конструируются там же (рисунок 3-8), вам, в общем, необходимо выполнить некоторые преобразования , дабы объекты были видны.
Заметьте, что изначально камера указывает в отрицательном направлении оси z .
Рисунок 3-8. Объект и точка обзора в начале координат
В простейшем случае вы можете передвинуть точку наблюдения назад, от объектов; эффект будет такой же, как если бы вы передвинули объекты вперед от точки наблюдения. Помните, что по умолчанию «вперед» – это значит в отрицательном направлении оси z ; если вы повернете точку наблюдения, «вперед» будет иметь другой смысл. Таким образом, чтобы поместить 5 единиц дистанции между точкой наблюдения и объектами, переместив точку наблюдения (как показано на рисунке 3-9), используйте следующую команду: glTranslatef(0.0,0.0,-5.0);
Эта команда передвигает объекты сцены на -5 единиц вдоль оси z . Она также эквивалентна передвижению камеры на +5 единиц вдоль оси z .
Рисунок 3-9. Разделение точки наблюдения и объекта

Теперь предположим, что вы хотите наблюдать объекты со стороны. Должны ли вы в этом случае выполнить команду поворота до или после команды переноса? Если вы мыслите в терминах фиксированной системы координат, для начала представьте объекты и камеру в начале координат. Сначала вы должны повернуть объекты, а затем отодвинуть их от камеры, чтобы выбранная сторона была видна. Поскольку вы знаете, что при подходе с фиксированной системой координат команды должны вызываться в обратном порядке – в том, в котором они будут иметь эффект, вы знаете, что сначала должны написать команду переноса, а затем – поворота.
Теперь используем подход с локальной системой координат. В этом случае думайте о передвижении объекта и его локальной системы координат от начала координат, а затем о повороте с использованием теперь уже перенесенной системы координат. При таком подходе команды вызываются в том же порядке, в котором они применяются , так что перенос снова будет первым, а поворот – вторым. Таким образом, последовательность команд преобразований для получения желаемого результата должна быть следующей: glTranslatef(0.0,0.0,-5.0); glRotatef(90.0,0.0,1.0,0.0);
Если у вас возникают проблемы с понимаем матричных манипуляций, попробуйте разобрать оба подхода с фиксированной и локальной системами координат и оценить, имеет ли один из них смысл. Заметьте, что в фиксированной системе координат вращение всегда происходит вокруг фиксированного начала координат, а в локальной
– вокруг изменяющегося начала координат. Вы также можете попробовать использовать команду библиотеки утилит gluLookAt() , которая описана далее.
3.2.3.2 Использование команды библиотеки утилит gluLookAt()
Часто программисты конструируют сцену в районе начала координат или в некотором другом месте, а затем хотят посмотреть на нее с определенной точки обзора для получения лучшего вида. Как и говорит ее имя, команда из библиотеки утилит
gluLookAt() разработана как раз для подобных целей. Она принимает три набора аргументов, которые задают точку наблюдения, прицельную точку (точку, на которую направлена камера) и направление, которое следует считать верхним. Выберите точку обзора, чтобы получить желаемый вид сцены. Прицельная точка, как правило, находится где-то в середине сцены. (Если вы строите сцену в начале координат, то, вероятно, оно и будет прицельной точкой.) Несколько сложнее, видимо, задать верный вектор верхнего направления. Если вы строите сцену в или около начала координат и считаете, что положительное направление оси yуказывает вверх, то это и есть ваш вектор верхнего направления для gluLookAt() . Однако если вы разрабатываете

симулятор полетов, верхним является направление перпендикулярное крыльям самолета.
Команда gluLookAt() может быть полезна, например, если вы хотите скользить по ландшафту. С объемом видимости симметричным по x и y точка (eyex , eyey , eyez ) может всегда задаваться как лежащая в центре изображения, и вы можете исполнять серию команд для незначительного изменения этой точки, таким образом, скользя по сцене. void gluLookAt (GLdouble eyex , GLdouble eyey , GLdouble eyez , GLdouble centerx ,
GLdouble centery , GLdouble centerz ,
GLdouble upx , GLdouble upy , GLdouble upz );
Задает видовую матрицу и умножает на нее текущую матрицу. Выбранная точка обзора задается аргументами eyex , eyey и eyez . Аргументы centerx , centery и centerz задают любую точку на линии обзора, но обычно они задают точку где-то в середине обозреваемой сцены. Аргументы upz , upy и upz определяют, какое направление считается верхним (то есть направление от дна до вершины объема видимости).
По умолчанию камера находится в начале координат, направлена вдоль отрицательного направления оси z , а вектор верхнего направления совпадает с положительным направлением оси y . Таким образом, следующий вызов восстанавливает ситуацию по умолчанию: gluLookAt(0.0,0.0,0.0,0.0,0.0,-100.0,0.0,1.0,0.0);
Величина z -координаты прицельной точки здесь равна -100.0 , но на самом деле она может быть любой отрицательной величиной, поскольку в этом случае направление обзора останется неизменным. Для описанного случая нет необходимости вызывать
gluLookAt() , поскольку это – установка по умолчанию (рисунок 3-10). (Линии из точки наблюдения представляют собой объем видимости, задающий видимое пространство.)
Рисунок 3-10. Позиция точки наблюдения по умолчанию
Заметьте, что gluLookAt() является частью библиотеки утилит, а не базовой командой
OpenGL. Это произошло не потому, что gluLookAt() бесполезна, а потому, что она инкапсулирует несколько базовых команд OpenGL, а именно glTranslate*() и
glRotate*() . Чтобы понять это представьте, что камера находится в выбранной точке обзора и направлена в соответствии с желаемым направлением обзора, как задано
gluLookAt() и сцена находится в начале координат. Чтобы отменить действия
gluLookAt() вам требуется поместить камеру в начале координат и установить направление обзора совпадающим с отрицательным направлением оси z (то есть

привести видовое преобразование к ситуации по умолчанию). Простой перенос передвинет камеру в начало координат. Вы легко можете представить себе серию поворотов вокруг осей фиксированной системы координат, которые в итоге ориентируют камеру в отрицательном направлении оси z . Поскольку OpenGLпозволяет задавать повороты вокруг любой выбранной оси , вы можете выполнить требуемый поворот с помощью всего одной команды glRotate*() .
Замечание
:
Вы можете иметь только одно активное видовое преобразование
Вы не можете комбинировать эффекты двух видовых преобразований
фотокамера не может быть установлена на двух треногах одновременно
).
Если вы хотите изменить позицию камеры
, убедитесь
, что вы вызвали
glLoadIdentity()
для стирания эффекта от текущего видового преобразования
Дополнительно: Чтобы трансформировать любой вектор до совпадения (по направлению) с другим вектором (например, с отрицательным направлением оси z ) требуется произвести некоторые математические расчеты. Ось, вокруг которой следует производить вращение, получается как векторное произведение двух нормализованных векторов. Чтобы найти угол вращения нормализуйте оба данных вектора. Косинус нужного угла между векторами эквивалентен скалярному произведению между нормализованными векторами. Угол поворота вокруг оси, полученный как векторное произведение всегда находится между 0 и 180 градусами.
Заметьте, что вычисление угла между двумя нормализованными векторами посредством взятия арккосинуса их скалярного произведения дает весьма неточные результаты, особенно при малых углах. Однако этот метод работает.
3.2.3.3 Создание пользовательской функции
Дополнительно: Для некоторых специализированных приложений может понадобиться собственная функция преобразования. Поскольку это делается достаточно редко и, в любом случае, это достаточно сложный, не шаблонный процесс, он оставляется читателю в качестве упражнения. Далее приведены два примера таких функций.
Предположим, что вы разрабатываете симулятор полетов, и вам требуется изображать мир с точки зрения пилота в кабине самолета. Самолет находится в точке с координатами (x , y , z ). Предположим также, что самолет характеризуется тремя углами своего наклона относительно центра своей гравитации – roll , pitch и heading . Для изображения мира глазами пилота может быть использована следующая функция: void pilotView(GLdouble planex, GLdouble planey, GLdouble planez, GLdouble roll,
GLdouble pitch, GLdouble heading)
{ glRotated(roll,0.0,0.0,1.0); glRotated(pitch,0.0,1.0,0.0); glRotated(heading,1.0,0.0,0.0); glTranslated(-planex,-planey,-planez);
}
Теперь предположим, что вашему приложению требуется вращать камеру вокруг объекта, находящегося в начале координат. В этом случае вы, вероятно, захотите задавать видовое преобразование в терминах полярной системы координат. Допустим, что переменная distance задает радиус орбиты, то есть расстояние от камеры до начала координат. (Вначале камера отодвигается на distance единиц вдоль положительного направления оси z .) Переменная azimuth задает угол вращения камеры вокруг объекта в плоскости xy y . Похожим образом,
elevation – это угол вращения камеры в плоскости yz , отмеряемый от положительного направления оси z . Наконец, twist представляет собой угол вращения объема видимости вокруг линии обзора. В этом случае подойдет следующая функция.

void polarView(GLdouble distance, GLdouble twist, GLdouble elevation, GLdouble azimuth)
{ glTranslated(0.0,0.0,-distance); glRotated(-twist,0.0,0.0,1.0); glRotated(-elevation,1.0,0.0,0.0); glRotated(azimuth,0.0,0.0,1.0);
}
3.3 Проекционные трансформации
В предыдущем разделе объяснялось, как задать нужную видовую матрицу для применения требующихся модельных и видовых преобразований. В этом разделе объясняется, как определить нужную матрицу проекции, которая также используется для преобразования вершин в вашей сцене. Помните, что до выполнения любых команд преобразований, описанных в этом разделе, следует вызвать glMatrixMode(GL_PROJECTION); glLoadIdentity(); чтобы следующие команды изменяли именно матрицу проекции, а не видовую матрицу и во избежание составных проекционных преобразований. Поскольку команда проекционного преобразования полностью описывает отдельную трансформацию, обычно вам не нужно комбинировать одну трансформацию с другой.
Назначение проекционного преобразования заключается в определении объема
видимости , который используется двумя путями. Объем видимости определяет, как объект проецируется на экран (с использованием перспективной или параллельной проекции), он также определяет, какие объекты или части объектов будут отсечены в результирующем изображении. Точку наблюдения, о которой мы говорили раньше, вы можете представить себе находящейся на одном из концов объема видимости.
3.3.1 Перспективная проекция
Наиболее узнаваемой характеристикой перспективной проекции является уменьшение на расстоянии: чем дальше объект находится от камеры (точки наблюдения), тем меньше он будет в финальном изображении. Это происходит потому, что объем видимости перспективной проекции имеет форму усеченной пирамиды (пирамиды, верхушка которой отрезана плоскостью, параллельной ее основанию). Объекты, попадающие в объем видимости проецируются из вершины пирамиды, где находится точка наблюдения. Более близкие к точке наблюдения объекты получаются крупнее, поскольку они занимают пропорционально большее пространство объема видимости.
Более далекие объекты оказываются меньше, поскольку они находятся в более широкой части усеченной пирамиды объема видимости. Данный метод проецирования используется для анимации , визуальной симуляции и в любых других приложениях, претендующих на некоторую долю реализма, так как перспективное проектирование похоже на то, как видит человеческий глаз (или камера).
Команда определения объема видимости в форме усеченной пирамиды glFrustum() вычисляет матрицу, выполняющую перспективное проецирование, и умножает на нее текущую матрицу проекции (обычно единичную). Вспомните, что объем видимости используется для отсечения объектов лежащих вне него; четыре стороны пирамиды, ее основание и вершина (точнее, верхняя сторона) соответствуют шести отсекающим плоскостям объема видимости, как показано на рисунке 3-11. Объекты или части объектов вне этих плоскостей отсекаются и не выводятся в финальном изображении.
Заметьте, что glFrustum() не требует от вас указания симметричного объема видимости.

Рисунок 3-11. Объем видимости перспективной проекции, заданный командой glFrustum() void glFrustum (GLdouble left , GLdouble right , GLdouble bottom , GLdouble top ,
GLdouble near , GLdouble far );
Создает матрицу перспективного проецирования и умножает на нее текущую матрицу.
Объем видимости задается параметрами (left , bottom ,-near ) и (right , top ,-near ) определяющими координаты (x , y , z ) левого нижнего и правого верхнего углов ближней отсекающей плоскости; near и far задают дистанцию от точки наблюдения до ближней и дальней отсекающих плоскостей (они всегда должны быть положительными).
Пирамида имеет ориентацию в пространстве по умолчанию. Вы можете производить повороты или переносы для управления ее положением, но это весьма сложный процесс, которого почти всегда можно избежать.
Дополнительно: Пирамида не обязана быть симметричной и ее центральная ось не обязательно должна совпадать с осью z . Например, вы можете использовать
glFrustum() для создания такого изображения, как если бы вы смотрели через прямоугольное окно, причем это окно находится выше и правее вас. Фотографы используют этот прием для создания ложной перспективы. Вы можете использовать его, чтобы аппаратно визуализировать изображения с разрешением значительно выше обычного (например, для вывода на принтер). Предположим, вам требуется изображение с разрешением вдвое большим разрешения вашего экрана. Нарисуйте изображение 4 раза, каждый раз используя пирамидальный объем видимости для покрытия всего экрана одной четвертью изображения. После того, как каждая четверть будет выведена на экран, вы можете считать пиксели , собрав, таким образом, данные для изображения высокого разрешения.
Рисунок 3-12. Объем видимости перспективной проекции, заданный командой gluPerspective

Хотя glFrustum() концептуально ясна, ее использование не является интуитивно понятным. Вместо нее вы можете попробовать использовать функцию gluPerspective() из библиотеки утилит. Эта функция создает объем видимости той же формы, что и
glFrustum() , но вы задаете его параметры иным путем. Вместо указания углов ближней отсекающей плоскости, вы задаете угол визуального охвата (или тета) в вертикальном направлении y и отношение ширины к высоте (x/y ). (Для квадратной части экрана отношение ширины к высоте равно 1.0 .) Этих двух параметров достаточно для определения неусеченной пирамиды вдоль направления обзора (рисунок 3-12). Вы также задаете дистанцию между точкой наблюдения и ближней и дальней отсекающими плоскостями, таким образом, отсекая пирамиду.
Заметьте, что gluPerspective() ограничена созданием только пирамид симметричных вдоль линии обзора по x - и y -осям, но обычно это именно то, что и требуется. void

Решили изучить OpenGL, но знаете, с чего начать? Сделали подборку материалов.

Что есть OpenGL

OpenGL (открытая графическая библиотека) - один из наиболее популярных графических стандартов для работы с графикой. Программы, написанные с её помощью можно переносить практически на любые платформы, получая одинаковый результат. OpenGL позволяет не писать программы под оборудование, а воспользоваться существующими разработками. Разрабатывает OpenGL компания Silicon Graphics, при сотрудничестве с другим технологическими гигантами.

С точки зрения программирования, OpenGL - это программный интерфейс для растровой графики, таких как графические ускорители. Он включает в себя около 150 различных команд, с помощью которых программист может определять различные объекты и производить рендеринг.

Материалы для изучения

Туториалы

Онлайн-курсы

  • Lynda - «Курс по OpenGL»;
  • Токийский университет - «Интерактивная компьютерная графика»;
  • Университет Сан-Диего - «Основы компьютерной графики».

Книги

На русском

1. Д. Шрайнер - OpenGL Redbook - скачать;

Книга - официальное руководство по изучению OpenGL. Последние издания практически полностью отличаются от первоначальных вариантов, автор обновляет её в соответствии с изменениями версий. По мнению сотен специалистов, работающих с Open GL, эта книга является первым, что должен взять в руки желающий изучить технологию.

2. Д. Вольф - Open GL 4. Язык шейдеров. Книга рецептов (2015) - скачать;

В этой книге рассматривается весь спектр приемов программирования на GLSL, начиная с базовых видов шейдеров – вершинных и фрагментных, – и заканчивая геометрическими, вычислительными и шейдерами тесселяции. Прочтя ее, вы сможете задействовать GPU для решения самых разных задач.

3. Д. Гинсбург - OpenGL ES 3.0. Руководство разработчика (2014) - купить;

В данной книге автор рассматривает весь API и язык для написания шейдеров. Также вы найдете советы по оптимизации быстродействия, максимизации эффективности работы API и GPU и полном использовании OpenGL ES в широком спектре приложений.

4. В. Порев - Компьютерная графика (2002) - скачать;

В книге рассмотрены способы работы с компьютерной графикой, частые проблемы, приведены примеры программ на C++.

На английском

1. П. Ширли - Основы компьютерной графики (2009) - ;

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

2. Э. Ангел - Интерактивная компьютерная графика - купить ;

Эта книга предназначена для всех студентов, изучающих информатику и программирование углубленно. Компьютерная анимация и графика - уже не так сложно, как раньше. Следуя своему утверждению, автор написал книгу максимально понятным языком.

Знакомство с 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. glVertex2i(250 , 450 ) ;
  3. glVertex2i(250 , 150 ) ;
  4. glVertex2i(550 , 150 ) ;
  5. glVertex2i(550 , 450 ) ;
  6. glEnd() ;

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

Для платформонезависимой работы с окнами можно использовать библиотеку . 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:

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

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

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

Итог

Все! Можно компилировать. Должно получиться что-то вроде этого: