Ю.М. Баяковский, А.В. Игнатенко - Начальный курс OpenGL (DOC) (1124366), страница 5
Текст из файла (страница 5)
Также можно указывать какой тип граней отображать на экране. Для этого сначала надо установить соответствующий режим вызовом команды glEnable (GL_CULL_FACE), а затем выбрать тип отображаемых граней с помощью команды
void glCullFace (GLenum mode)
Вызов с параметром GL_FRONT приводит к удалению из изображения всех лицевых граней, а с параметром GL_BACK — обратных (установка по умолчанию).
Кроме рассмотренных стандартных примитивов в библиотеках GLU и GLUT описаны более сложные фигуры, такие как сфера, цилиндр, диск (в GLU) и сфера, куб, конус, тор, тетраэдр, додекаэдр, икосаэдр, октаэдр и чайник (в GLUT). Автоматическое наложение текстуры предусмотрено только для фигур из библиотеки GLU (создание текстур в OpenGL будет рассматриваться в главе 6).
3.4- Дисплейные списки
47
Например, чтобы нарисовать сферу или цилиндр, надо сначала создать объект специального типа GLUquadricObj с помощью команды
GLUquadricObj * gluNewQuadric (void ) ;
а затем вызвать соответствующую команду:
void gluSphere (GLUquadricObj * qobj , GLdouble radius , GLint slices , GLint stacks)
void gluCylinder (GLUquadricObj * qobj , GLdouble baseRadius , GLdouble topRadius , GLdouble height , GLint slices , GLint stacks)
где параметр slices задает количество разбиений вокруг оси z, a stacks — вдоль оси ъ.
Более подробную информацию об этих и других командах построения примитивов можно найти в приложении А.
3.4. Дисплейные списки
Если мы несколько раз обращаемся к одной и той же группе команд, то их можно объединить в так называемый дисплейный список (display list) и вызывать его при необходимости. Для того, чтобы создать новый дисплейный список, надо поместить все команды, которые должны в него войти, между следующими операторными скобками:
void glNewList (GLuint list , GLenum mode) void glEndList ()
48 Глава 3. Рисование геометрических объектов
Для различения списков используются целые положительные числа, задаваемые при создании списка значением параметра list. Параметр mode определяет режим обработки команд, входящих в список:
GL COMPILE —команды записываются в список без выполнения;
GL_COMPILE_AND_EXECUTE —команды выполняются, а затем записываются в список.
После того, как список создан, его можно вызвать командой
void glCallList (GLuint list)
указав в параметре list идентификатор нужного списка.
Чтобы вызвать сразу несколько списков, можно воспользоваться командой
void glCallLists (
GLsizei n, GLenum type, const GLvoid * lists)
вызывающей п списков с идентификаторами из массива lists, тип элементов которого указывается в параметре type. Это могут быть типы GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_UNSIGNED_INT и некоторые другие. Для удаления списков используется команда
void glDeleteLists (GLint list , GLsizei range)
которая удаляет списки с идентификаторами ID из диапазона list < ID < list + range — 1. Пример:
glNewList(l, GL_COMPILE); glBegin (GLJTRIANGLES);
glVertex3f (l.Of , l.Of, l.Of); glVertex3f (10.Of , l.Of, l.Of); glVertex3f (10-Of , 10.Of, l.Of);
3.5. Массивы вершин
49
glEnd(); glEndList ()
glCallList (1);
Дисплейные списки в оптимальном (скомпилированном) виде хранятся в памяти сервера, что позволяет рисовать примитивы в такой форме максимально быстро. В то же время большие объемы данных занимают много памяти, что влечет, в свою очередь, падение производительности. Такие большие объемы (больше нескольких десятков тысяч примитивов) лучше рисовать с помощью массивов вершин.
3.5. Массивы вершин
Если вершин много, то, чтобы не вызывать для каждой команду glVertex, удобно объединять вершины в массивы, используя команду
void glVertexPointer (GLint size , GLenum type,
GLsizei stride , void* ptr)
которая определяет способ хранения и координаты вершин. При этом size определяет число координат вершины (может быть равен 2, 3, 4), type определяет тип данных (может быть равен GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE). Иногда удобно хранить в одном массиве другие атрибуты вершины, тогда параметр stride задает смещение от координат одной вершины до координат следующей; если stride равен нулю, это значит, что координаты расположены последовательно. В параметре ptr указывается адрес, где находятся данные.
Аналогично можно определить массив нормалей, цветов и некоторых других атрибутов вершины, используя команды
void glNormalPointer ( GLenum type , GLsizei stride ,
50
Глава 3. Рисование геометрических объектов
void ^pointer ) void glColorPointer ( GLint size , GLenum type ,
GLsizei stride , void *pointer )
Для того, чтобы эти массивы можно было использовать в дальнейшем, надо вызвать команду
void glEnableClientState (GLenum array)
с параметрами GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY соответственно.
После окончания работы с массивом желательно вызвать команду
void glDisableClientState (GLenum array)
с соответствующим значением параметра array.
Для отображения содержимого массивов используется команда
void glArrayElement (GLint index)
которая передает OpenGL атрибуты вершины, используя элементы массива с номером index. Это аналогично последовательному применению команд вида glColor, glNormal, glVertex с соответствующими параметрами. Однако вместо нее обычно вызывается команда
void glDrawArrays (GLenum mode, GLint first ,
GLsizei count)
рисующая count примитивов, определяемых параметром mode, используя элементы из массивов с индексами от first до first + count — 1. Это эквивалентно вызову последовательности команд glArrayElement() с соответствующими индексами.
В случае, если одна вершина входит в несколько примитивов, вместо дублирования ее координат в массиве удобно использовать ее индекс.
Для этого надо вызвать команду
3.6. Контрольные вопросы
51
void glDrawElements (GLenum mode, GLsizei count,
GLenum type, void* indices)
где indices—это массив номеров вершин, которые надо использовать для построения примитивов, type определяет тип элементов этого массива: GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, a count задает их количество.
Важно отметить, что использование массивов вершин позволяет оптимизировать передачу данных на сервер OpenGL, и, как следствие, повысить скорость рисования трехмерной сцены. Такой метод определения примитивов является одним из самых быстрых и хорошо подходит для визуализации больших объемов данных.
3.6. Контрольные вопросы
-
Что такое функция обратного вызова и как функции обратного вызова могут быть использованы для работы с OpenGL?
-
Для чего нужна функция обновления изображения и что она делает?
-
Что такое примитив в OpenGL?
-
Что такое атрибут? Перечислите известные вам атрибуты вершин в OpenGL.
-
Что в OpenGL является атомарным примитивом? Какие типы примитивов вы знаете?
-
Для чего в OpenGL используются команды glEnable и glDisable ?
52
Глава 3. Рисование геометрических объектов
-
Что такое операторные скобки и для чего они используются в OpenGL?
-
Что такое дисплейные списки? Как определить список и как вызвать его отображение?
-
Поясните организацию работы с массивами вершин и их отличие от дисплейных списков.
10) Поясните работу команды glDrawElementsQ.
3.6. Контрольные вопросы
53
i •
•о •.
з • 1
GL POINTS
3 4 GL LINES
M.
GL LINE STRIP
5
C*
GL LINE LOOP
GL POLYGON
GL_QUADS
A>±
GL_QUAD_STRIP
GL TRIANGLES
.25^
GL TRIANGLE FAN
GL TRIANGLE STRIP
Рис. З.1. Примитивы OpenGL.
Глава 4.
Преобразования объектов
В OpenGL используются как основные три системы координат: левосторонняя, правосторонняя и оконная. Первые две системы являются трехмерными и отличаются друг от друга направлением оси z: в правосторонней она направлена на наблюдателя, в левосторонней — в глубину экрана. Ось х направлена вправо относительно наблюдателя, ось у — вверх.
Левосторонняя система используется для задания значений параметрам команды gluPerspectiveQ, glOrtho(), которые будут рассмотрены в пункте 4.3. Правосторонняя система координат используется во всех остальных случаях. Отображение трехмерной информации происходит в двухмерную оконную систему координат.
Строго говоря, OpenGL позволяет путем манипуляций с матрицами моделировать как правую, так и левую систему координат. Но на данном этапе лучше пойти простым путем и запомнить: основной системой координат OpenGL является правосторонняя система.
55
56
Глава 4- Преобразования объектов
(в)
Рис. 4.1. Системы координат в OpenGL. (a) — правосторонняя, (б) — левосторонняя, (в) — оконная.
4.1. Работа с матрицами
Для задания различных преобразований объектов сцены в OpenGL используются операции над матрицами, при этом различают три типа матриц: модельно-видовая, матрица проекций и матрица текстуры. Все они имеют размер 4x4. Видовая матрица определяет преобразования объекта в мировых координатах, такие как параллельный перенос, изменение масштаба и поворот. Матрица проекций определяет, как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты), а матрица текстуры определяет наложение текстуры на объект.
Умножение координат на матрицы происходит в момент вызова соответствующей команды OpenGL, определяющей координату (как правило, это команда glVertex.)
Для того чтобы выбрать, какую матрицу надо изменить, используется команда: