Кафедра: Информационные технологии
Трехмерная графика OpenGL
1. Теоретическая часть
1.1 Подключение графической библиотеки OpenGL к интерфейсу Windows
Стандарт реализации OpenGL для Windows требует выполнения некоторых настроек, связанных с особенностями операционной системы. Для того чтобы оконная система могла работать с OpenGL, необходимо провести ее инициализацию и сконфигурировать буфер фрейма.
Система OpenGL, как и любое другое приложение Windows, нуждается в ссылке на окно, на котором будет осуществляться воспроизведение. Ссылка на контекст воспроизведения – величина типа HGLRC (Handle to OpenGL Rendering Context) – связывает OpenGL с оконными системами Windows.
Для получения этого контекста OpenGL нуждается в величине типа HDC (контекст устройства) окна, на который будет осуществляться вывод.
Таким образом, чтобы начать работать с командами OpenGL, приложение должно создать один или несколько контекстов воспроизведения для потока, и сделать текущим один из них. Каждый поток при этом может иметь один и только один текущий контекст воспроизведения, который ассоциирован с определённым контекстом устройства.
Прежде чем получить контекст воспроизведения, сервер OpenGL должен получить детальные характеристики используемого оборудования. Эти характеристики хранятся в специальной структуре, тип которой TPixelFormatDescriptor (описание формата пикселей). Формат пикселей определяет число бит на пиксел, конфигурацию буфера цвета и вспомогательных буферов используемых для вывода изображения.
Для установки формата пикселей необходимо написать соответствующую процедуру, типичный пример которой приведён в приложении 2.
Для работы с контекстом воспроизведения в Win32 API реализованы следующие функции.
wglCreateContext(dc);
Функция создаёт контекст воспроизведения OpenGL, который подходит для рисования на устройстве, определённом дескриптором dc. При успешном завершении функция возвращает дескриптор созданного контекста воспроизведения OpenGL, и NULL – в случае неудачи.
Текущий контекст воспроизведения потока должен быть единственным. Следующая функция позволяет определить контекст воспроизведения для контекста устройства.
wglMakeCurrent (dc, hrc);
При завершении работы, необходимо, чтобы контекст никем не использовался. Для этого достаточно выполнить вызов функции:
wglMakeCurrent (0,0);
Завершая работу с OpenGL необходимо удалить контекст воспроизведения. Для этой цели используется функция:
wglDeleteContext(hrc);
После того как удалён контекст воспроизведения, следует удалить и ассоциированный с ним контекст устройства.
Структуру приложения, использующего OpenGL, можно изобразить в виде схемы (рис. 1)
1.2 Синтаксис команд
OpenGL
Для того чтобы команды OpenGL были доступны в проекте, необходимо указать библиотеку в списке используемых модулей.
Все команды начинаются с префикса gl, затем идёт имя команды, цифра и суффикс. Цифра в окончании соответствует количеству аргументов, буква показывает требуемый тип аргумента.
Если имя команды заканчивается на v
(векторная форма), то аргументом её служит указатель на массив значений.
Например: Если последние три символа в имени команды 3fv
, то её аргумент – адрес массива трёх вещественных чисел.
В общем виде команду можно представить:
glCommandName {1,2,3,4} {b, s, i, f, d, ub, us, ui} {v} (arguments)
Таблица 1.1. Возможные типы аргументов
Символ
|
Обозначение типа в OpenGL
|
Расшифровка
|
b
|
GLbyte
|
Байтовый
|
s
|
GLshort
|
Короткий целый
|
i
|
GLint
|
Целый
|
d
|
GLdouble
|
Вещественный двойной точности
|
f
|
GLfloat
|
Вещественный
|
ub
|
GLubyte
|
Байтовый, беззнаковый
|
us
|
GLushort
|
Короткий целый, беззнаковый
|
ui
|
GLuint
|
Целый, беззнаковый
|
Почти всегда предпочтительно использовать команду в вещественной форме, поскольку хранит данные OpenGL именно в вещественном формате.
1.3 Рисование примитивов
Процедура рисования заключается в командные скобки
glBegin(mode)
… // команды, указывающие вершины фигуры
glEnd;
Главное назначение командных скобок – это задание режима, определяющего как соединять точки (вершины). Вершины задаются своими координатами (количество координат зависит от пространства изображения) с помощью команд glVertex {2,3,4} {s, i, f, d} (arg).
Режим (
mode
)
, задающий правило соединения точек, определяет примитив. К примитивам относятся точки, линии, связанные линии, замкнутые линии, треугольники, связанные треугольники, четырёхугольники, связанные четырёхугольники и многоугольники.
Пример: задание стороны куба
glBegin (GL_POLYGON);
glNormal3f (0.0, 0.0, 1.0);
glVertex3f (1.0, 1.0, 1.0);
glVertex3f (-1.0, 1.0, 1.0);
glVertex3f (-1.0, -1.0, 1.0);
glVertex3f (1.0, -1.0, 1.0);
glEnd;
Таблица 1.2. Значение параметра mode
mode
|
Описание
|
GL_POINTS
|
Каждый вызов glVertex задает отдельную точку. Рисует N точек
|
GL_LINES
|
Каждая пара вершин задает отрезок. Рисует N/2 линий
|
GL_LINE_STRIP
|
Рисуется ломанная. Элементы n и n+1 определяют отрезок n. рисуется N – 1 отрезков
|
GL_LINE_LOOP
|
Рисуется ломанная, причем ее последняя точка соединяется с первой. элементы n и n+1 определяют отрезок n. последняя линия определяется элементом N и 1. рисуется N отрезков
|
GL_TRIANGLES
|
Каждые три вызова glVertex задают треугольник. элементы 3n – 2, 3n‑1, и 3n определяют треугольник n. Рисуется N/3 треугольников.
|
GL_TRIANGLE_STRIP
|
Рисуются треугольники с общей стороной. Для нечетного n, элементы n, n+1, n+2 определяют треугольник n. Для нечетного n элементы n+1, n, n+2 определяют треугольник n. Рисуется N‑1 треугольников.
|
GL_TRIANGLE_FAN
|
Рисует группу соединенных треугольников. Один треугольник определяется для каждого элемента после двух предыдущих. Два последних элемента соединяются с первым. рисуется N – 2 треугольников.
|
GL_QUADS
|
Каждые четыре вызова glVertex задают четырехугольник. рисуется N/4 четырехугольника.
|
GL_QUAD_STRIP
|
Четырехугольники с общей стороной. соединяя чётные элементы с чётными, а нечётные с нечётными.
|
GL_POLYGON
|
Полигон. Элементы с 1 по N определяют этот полигон.
(при этом точки полигона сортируются так, чтобы грани у получившегося многоугольника не пересекались)
|
1.4 Визуализация сцены
Для создания сцены необходимо задать область вывода объектов и задать способ проецирования.
Если область вывода не задана явно, то в OpenGL используется установленная по умолчанию зона в виде куба видимости 2x2x2 с началом координат в центре куба (рис. 2).
Рис. 2. Вид системы координат Oxyz
Система координат в OpenGL Oxyz (рис. 2) расположена таким образом, что ось Oz направлена в сторону противоположную направления зрения. Окно видимости (Windows) масштабируется в пределах [-1; 1] по осям Ox, Oy. Изображение по умолчанию воспроизводится на плоскости z=0.
Существует два типа проецирования: параллельная проекция и перспективная. Ортогональная проекция – это частный случай параллельной проекции, при которой проецирующие лучи ортогональны картинной плоскости.
При ортогональном проецировании точка (x, y, z) на объекте проецируется в точку (x, y, 0) на плоскости проекции. В OpenGL ортогональная проекция, характеризуемая параллелепипедом видимости, задаётся функцией glOrtho(), объявленной следующим образом:
glOrtho (left, right, bottom, top, near, far)
Таким образом, видны все объекты, которые попали внутрь параллелепипеда видимости.
При проецировании, преобразование координат включает в себя этапы, изображённые на рис. 3. Сначала мировые координаты (система координат, в которой определяется положение объекта, положение точки наблюдения и экрана) преобразовываются в видовые координаты. При этом точки изображения остаются на своих местах, но система мировых координат переходит в систему видовых координат. Затем выполняется перспективное преобразование, добавляющее эффект перспективы в зависимости от расстояния от объекта до экрана и расстояние от точки наблюдения до экрана. Система трёхмерных видовых координат переходит в систему двухмерных экранных координат. При построении параллельной проекции перспективное преобразование не выполняется, и видовые координаты используются в качестве экранных координат (X, Y).
Рис. 3. Схема преобразования координат
1.5 Видовые преобразования
Видовые преобразования осуществляются с помощью матричных преобразований. В OpenGL текущая матрица преобразований является произведением двух матриц – матрицы модели и матрицы проецирования, при этом формируется единая матрица преобразования, которая применяется ко всем вершинам всех геометрических объектов.
Матрица модели
– glMatrixMode (GL_MODELVIEW) связана с координатами объектов. Это матрица в базисе видовых координат, она используется для построения картинки в том виде как её видит наблюдатель.
Матрица проецирования
– glMatrixMode (GL_PROJECTION). Матрица в системе координат устройства. Вычисляет нормализованные координаты, которые преобразуются в экранные после трансформаций, связанных с областью вывода.
Команда glLoadIdentity заменяет текущую матрицу единичной матрицей
(матрицей с единицами по главной диагонали и равными нулю всеми остальными элементами).
1.6 Аффинные преобразования
1.6.1 Масштабирование
Преобразование масштабирования увеличивает или уменьшает размеры объекта.
Команда масштабирования glScale (arg1, arg2, arg3) с тремя аргументами – коэффициентами масштабирования по каждой из осей.
Если масштабные множители больше единицы объект растягивается в заданном направлении, если меньше объект сжимается. Масштабные множители могут иметь отрицательные значения, при этом изображение переворачивается по соответствующей оси. При двумерных построениях значение коэффициента по оси Z игнорируется.
После команд рисования следует восстановить нормальный масштаб, чтобы каждое следующее обращение к обработчику перерисовки экрана не приводило бы к последовательному уменьшению / увеличению изображения.
1.6.2 Поворот
Для поворота изображения используется команда
glRotate (arg1, arg2, arg3, arg4)
с четырьмя аргументами:
arg1 – угол поворота (в градусах),
arg2, arg3, arg4 – вектор поворота.
1.6.3 Сдвиг
Преобразование сдвига смещает точки в новые позиции в соответствии с заданным вектором смещения. Перенос системы координат осуществляется командой
glTranslate (arg1, arg2, arg3)
arg1, arg2, arg3 – величины переноса по каждой из осей.
Для поворота вокруг произвольной фиксированной точки сначала нужно выполнить преобразование сдвига, совмещающую заданную фиксированную точку с началом координат, потом выполнить преобразование поворота вокруг начала координат, а затем обратное преобразование сдвига. Порядок манипуляции с системой координат: вначале перенос, затем поворот, по окончании рисования – в обратном порядке: поворот, затем перенос.
1.7 Закрашивание объектов сцены
В трёхмерном пространстве поверхность объектов характеризуется материалом. Материал может отражать, поглощать и пропускать свет различной длины волн. В зависимости от характеристик материала и от свойств источника света мы видим объекты различными. Свойства материала задаются с помощью команды glMaterialfv(). Характеристики свойств материала, определяют соответствующие им символьные константы, которые представлены в таблице 1.3.
Таблица 1.3. Характеристики свойств материала
GL_AMBIENT
|
рассеянный свет
|
GL_DIFFUSE
|
Параметр, указывающий насколько сильно этот цвет отражается поверхностью при её освещении
|
GL_EMISSION
|
излучаемый свет
|
GL_SHININESS
|
степень отраженного света
|
Зеркальный цвет задаёт цветовую гамму бликов материала, степень зеркального отражения определяет, насколько близка поверхность к идеальному зеркалу (определяется числом из интервала [0,128]).
Свойства материала задаются для внешней и внутренней стороны фигуры.
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,@MaterialFront);
glMaterialfv (GL_BACK, GL_AMBIENT_AND_DIFFUSE,@MaterialBack);
Существует несколько режимов рисования многоугольников.
Чтобы изменить метод отображения многоугольника используется команда:
glPolygonMode (GLenum face, Glenum mode)
Параметр mode определяет, как будут отображаться многоугольники, а параметр face устанавливает тип многоугольников, к которым будет применяться эта команда и могут принимать следующие значения:
Таблица 1.4. Значения параметров face и mode
GLenum face
|
GL_FRONT
|
для лицевых граней
|
GL_BACK
|
для обратных граней
|
GL_FRONT_AND_BACK
|
для всех граней
|
Glenum mode
|
GL_POINT
|
Отображаются вершины многоугольников
|
GL_LINE
|
представляется набором отрезков
|
GL_FILL
|
закрашиваются текущим цветом с учетом освещения и этот режим установлен по умолчанию.
|
Пример:
GlPolygonMode (GL_FRONT, GL_POINT);
GlPolygonMode (GL_ BACK, GL_LINE);
GlPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
1.8 Источники света
Без источника света изображения не видно. По умолчанию освещение отключено. Что бы инициализировать источник, и включить обработчик расчёта воздействия источника на объекты достаточно выполнить команды:
glEnable (gl_lighting);
glEnable (gl_light0);
Источник света по умолчанию располагается в пространстве с координатами (0,0,¥
), можно создавать источник света в любой точке пространства изображений.
Параметры источника света задаются с помощью команды,
glLightfv (source, parameter, pointer_to_array).
Первый параметр команды – идентификатор источника
Второй аргумент – символическая константа, задающая атрибут
Третий – ссылка на структуру, содержащую задаваемые значения для данного атрибута.
Таблица 1.5. Константы, задающие свойства окружающей среды и позицию источника света
GL_Position
|
задаёт позицию источника света, источник света не перемещается за системой координат (x, y, z, cos J)
|
GL_AMBIENT
|
рассеянный свет
|
GL_DIFFUSE
|
Параметр, указывающий насколько сильно этот цвет отражается поверхностью при её освещении
|
GL_SPECULAR
|
отраженный свет
|
GL_EMISSION
|
излучаемый свет
|
GL_SHININESS
|
степень отраженного света
|
GL_AMBIENT_AND_DIFFUSE
|
задаёт поглощение цвета поверхностью в рассеивающей составляющей
|
GL_SPOT_direction
|
направление света (x, y, z)
|
GL_SPOT_Cutoff
|
задаёт максимальный угол излучения источника света [0,90] и 180.
|
Для того чтобы внутренняя сторона объекта была видна необходимо включить освещенность для внутренней стороны многоугольника. Световая модель с освещением внутренней части многоугольника включается или выключается соответствующей функцией
glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, 1).
Второй аргумент 0 или 1 (вкл. или выкл.).
1.9 Наложение текстуры
Создание текстуры в памяти
После того как образ подготовлен, можно создавать текстуру в памяти. Для этого в OpenGL предусмотрены две команды: одна для одномерного и вторая для двумерного вариантов образа (обе работают только в режиме RGBA).
glTexlmage1D (void glTexlmage2D (
GLenum target, GLenum target,
GLint level, GLint level,
GLint components, GLint components,
GLsizei width, GLsizei width,
GLint border, GLsizei height,
GLenum format, GLint border,
GLenum type, GLenum format,
const GLvoid* pixels) GLenum type,
const GLvoid* pixels)
При создании текстуры можно определить несколько образов с различным разрешением. Если текстура имеет размер 2n
x2m
, то можно определить max {n, m} + 1 уменьшенных массивов. Первый имеет размер 2n
x2m
, второй – 2n
-1
x2m
-1
, и т.д., пока последний не будет иметь размер 1x1. Команды glTexImage
*
D
предоставляют возможность определить р = max {n, m} таких массивов, в каждом из которых хранится уменьшенный образ исходного изображения. Наличие таких массивов позволит OpenGL использовать меньший образ для меньшего объекта, а больший для большего. Другими словами, чем меньше объект, тем меньше его деталей удается рассмотреть.
Один элемент на экране может покрывать несколько элементов массива образа, и, чтобы избежать проблем, связанных с лестничным эффектом, необходимо учитывать все затрагивающие этот массив элементы.
Для этого определяются четыре точки в массиве образа, которые отображаются в четыре угла элемента на экране. Эти точки соединяются, и образуется четырехугольник. Значения попадающих в него элементов взвешиваются с учетом доли каждого элемента, содержащейся в многоугольнике, и затем суммируются.
Для учета особенностей текстуры необходимо настроить параметры текстуры, что можно сделать с помощью команды
glTexParameter
[i
, f, v
] (target, pname, param)
target
–
определяет, с какой текстурой предполагается работать, – одномерной или двумерной
pname
–
определяет символическое имя параметра текстуры:
ра
r
ат
определяет значение для параметра рпа
me
1.10 Использование дополнительных библиотек
Несмотря на то, что библиотека OpenGL предоставляет практически все возможности для моделирования и воспроизведения трёхмерных сцен, некоторые из функций, которые требуются при работе с графикой, напрямую отсутствуют в стандартной библиотеке OpenGL. Например, чтобы задать положение и направление камеры, с которой будет наблюдаться сцена, нужно самому рассчитывать модельную матрицу, а это далеко не все умеют. Поэтому для OpenGL существуют так называемые вспомогательные библиотеки.
Библиотека GLU уже стала стандартом и поставляется вместе с главной библиотекой OpenGL. В состав этой библиотеки вошли более сложные функции, например для того чтобы определить цилиндр или диск потребуется всего одна команда. Также в библиотеку вошли функции для работы со сплайнами, реализованы дополнительные операции над матрицами и дополнительные виды проекций.
Это независимая от платформы библиотека. Она реализует не только дополнительные функции OpenGL, но и предоставляет функции для работы с окнами, клавиатурой и мышкой. Для того чтобы работать с OpenGL в конкретной операционной системе, надо провести некоторую предварительную настройку и эта предварительная настройка зависит от конкретной операционной системы. С библиотекой GLUT всё намного упрощается, буквально несколькими командами можно определить окно, в котором будет работать OpenGL, определить прерывание от клавиатуры или мышки и всё это не будет зависеть от операционной системы.
Библиотека предоставляет функции, с помощью которых можно определять сложные правильные многогранники: куб, сфера, тор, конус, тетраэдр и додекаэдр, и даже можно с помощью одной команды определить сложный объект, типа чайник. Например, для воспроизведения куба достаточно выполнить команду: glutSolidCube(N), где N‑задаёт величину стороны грани куба. Перечень возможных функций приведен в приложении 3.
2. Практическая часть
2.1 Моделирование двумерных графических объектов и анимации с использованием графического стандарта OpenGL
Создать двумерную сцену. Изобразить две синусоиды в декартовой системе координат, используя примитивы OpenGL. Задать вращение в плоскости экрана вокруг произвольно выбранного центра таким образом, чтобы разные синусоиды имели различные скорости вращения.
2.2 Моделирование трёхмерных графических объектов и источников света с использованием OpenGL
Создать трёхмерную сцену. Пользуясь графическими объектами библиотеки GLUT (шар, конус, куб, тор, чайник и т.д.), создать в пространстве графические образы. Для элементов, из которых собраны объекты, задать различные свойства материала и различные режимы воспроизведения полигонов (точками, линиями, сплошное заполнение).
Расположить в произвольных точках пространства несколько источников света. Задать характеристики источникам света: один источник должен быть точечный, один направленный (типа «прожектор»). Цвет источников подбирается из эстетических соображений.
Задать движение каким-либо объектам сцены. Движение желательно описывать некоторым периодическим законом, чтобы перемещение объектов носило циклический характер и не требовало перезапуска программы для демонстрации.
1. Эйнджел Эдвард. Интерактивная компьютерная графика. Вводный курс на базе OpenGL, 2 изд.: Пер. с англ. – М.: Издательский дом «Вильямс», 2001.–592 с.:ил.
2. Ву Мейсон, Нейдер Джеки, Девис Том, Шрайнер Дейв. OpenGL. Официальное руководство программиста: Пер. с англ. СПб: ООО «ДиаСофтЮП», 2002. – 592 с.
3. Тихомиров Ю. Программирование трёхмерной графики – СПб.:BHV – Санкт-Петербург, 1998. – 256 с., ил.
4. Краснов М. OpenGL. Графика в проектах Delphi.–СПб.:БХВ – Санкт-Петербург, 2000.–352 с.:ил.
5. Роджерс Д. Алгоритмические основы машинной графики: Пер. с англ. – М.: Мир, 1989. – 512 с., ил
|