Документ взят из кэша поисковой машины. Адрес оригинального документа : http://graphics.cs.msu.ru/sites/default/files/gltutorialcourse2.pdf
Дата изменения: Fri Sep 28 15:01:33 2007
Дата индексирования: Sun Apr 10 01:46:53 2016
Кодировка: Windows-1251

Поисковые слова: внешние планеты
МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИМЕНИ М.В. ЛОМОНОСОВА

ФАКУЛЬТЕТ ВЫЧИСЛИТЕЛЬНОЙ МАТЕМАТИКИ И КИБЕРНЕТИКИ ЛАБОРАТОРИЯ КОМПЬЮТЕРНОЙ ГРАФИКИ И МУЛЬТИМЕДИА

Ю.М. Баяковский, А.В. Игнатенко
НАЧАЛЬНЫЙ КУРС OPENGL

ПЛАНЕТА ЗНАНИЙ
Москва 2007


УДК 681.3.07 ББК 32.973.26-018.2 Б34

Баяковский Ю.М., Игнатенко А.В. Начальный курс Op enGL. М.: ?Планета Знаний, 2007. 221c. ISBN 978-5-903242-02-3

Настоящая книга представляет собой практическое руководство по работе с графической библиотекой OpenGL. Руководство разработано с учетом опыта чтения курса ?Компьютерная графика? на факультете ВМиК МГУ им. М.В. Ломоносова. Книга включает в себя описание базовых возможностей OpenGL и приемы работы с библиотекой, вопросы оптимизации приложений и использования OpenGL в различных средах программирования. Книга снабжена вопросами и практическими заданиями. Руководство рассчитано на читателей, знакомых с языками программирования С/C++ и имеющих представление о базовых алгоритмах компьютерной графики. Рекомендуется студентам математических и прикладных специальностей, аспирантам, научным сотрудникам и всем желающим изучить OpenGL в сжатые сроки. Издание подготовлено в рамках образовательной программы ?Формирование системы инновационного образования в МГУ?. Рецензенты: Шикин Е.В., профессор, доктор физ.-мат. наук, ф-т ВМиК МГУ Крылов А.С., кандидат физ.-мат. наук, ф-т ВМиК МГУ

ISBN 978-5-903242-02-3

ї

Баяковский Ю.М., Игнатенко А.В. ООО ?Планета Знаний, 2007

ї


Оглавление
Предисловие Введение ......................... 7 11

...........................

I

Основы Op enGL

15
17

1. Графический процесс и Op enGL

1.1. 1.2. 1.3. 1.4. 1.5. 1.6. 1.7.

Графический процесс . . . . . . . . . . . . . . . . . Геометрические модели . . . . . . . . . . . . . . . . Анимация . . . . . . . . . . . . . . . . . . . . . . . . Материалы . . . . . . . . . . . . . . . . . . . . . . . Освещение ....................... .................

17 19 20 21 22 22 23
25

Виртуальная камера

Алгоритм экранизации . . . . . . . . . . . . . . . .

2. Введение в Op enGL

2.1. 2.2. 2.3. 2.4. 2.5. 2.6.

Основные возможности . . . . . . . . . . . . . . . . Интерфейс Op enGL . . . . . . . . . . . . . . . . . . Архитектура Op enGL . . . . . . . . . . . . . . . . . Синтаксис команд . . . . . . . . . . . . . . . . . . . Пример приложения Контрольные вопросы 3 ................. ................

25 26 28 30 31 36


4

Оглавление
39

3. Рисование геометрических объектов

3.1. 3.2. 3.3. 3.4. 3.5. 3.6.

Процесс обновления изображения . . . . . . . . . . Вершины и примитивы . . . . . . . . . . . . . . . . Операторные скобки glBegin / glEnd Дисплейные списки ........ .................. ................

39 41 43 47 49 51
55

Массивы вершин . . . . . . . . . . . . . . . . . . . . Контрольные вопросы

4. Преобразования объектов

4.1. 4.2. 4.3. 4.4. 4.5.

Работа с матрицами . . . . . . . . . . . . . . . . . . Модельно-видовые преобразования . . . . . . . . . Проекции . . . . . . . . . . . . . . . . . . . . . . . . Область вывода .................... ................ Контрольные вопросы

56 58 60 63 64
65

5. Материалы и освещение

5.1. 5.2. 5.3. 5.4. 5.5.

Модель освещения . . . . . . . . . . . . . . . . . . . Спецификация материалов . . . . . . . . . . . . . . Описание источников света Создание эффекта тумана Контрольные вопросы ............. ..............

65 67 69 73 74
77

................

6. Текстурирование

6.1. 6.2. 6.3. 6.4.

Подготовка текстуры

................. .......... ............... ................

77 81 84 87
89

Наложение текстуры на объекты Текстурные координаты Контрольные вопросы

7. Операции с пикселями

7.1. 7.2. 7.3. 7.4. 7.5.

Смешивание изображений и прозрачность . . . . . Буфер-накопитель . . . . . . . . . . . . . . . . . . . Буфер маски . . . . . . . . . . . . . . . . . . . . . . Управление растеризацией . . . . . . . . . . . . . . Контрольные вопросы ................

90 93 94 96 98


Оглавление
II Приемы работы с Op enGL

5

99
101

8. Графические алгоритмы на основе Op enGL

8.1. 8.2. 8.3. 8.4.

Устранение ступенчатости Построение теней

..............

101 103 109 113
115

...................

Зеркальные отражения . . . . . . . . . . . . . . . . Контрольные вопросы ................

9. Оптимизация программ

9.1. 9.2. 9.3.

Организация приложения

.............. ...........

115 120 128

Оптимизация вызовов Op enGL Контрольные вопросы

................

III

Создание приложений с Op enGL

131
133

10. Op enGL-приложения с помощью GLUT

10.1. Структура GLUT-приложения . . . . . . . . . . . . 10.2. GLUT в среде Microsoft Visual C++ 6.0 10.3. GLUT в среде Microsoft Visual C++ 2005 10.4. GLUT в среде Borland C++ Builder 6 ...... .....

133 137 139 140 141
145

.......

10.5. GLUT в среде Borland C++ Builder 2006 . . . . . .
11. Использование Op enGL в MFC и VCL

11.1. Контекст устройства

................. ............ ........

146 147 148 149 150 153
157

11.2. Установка формата пикселей

11.3. Контекст рисования (render context) 11.4. Класс GLRC

...................... ...........

11.5. Использование Op enGL c MFC

11.6. Использование Op enGL c VCL . . . . . . . . . . . .
12. Op enGL в .NET

12.1. GLUT в среде Microsoft Visual C# 2005

......

157 160

12.2. Использование Op enGL в WindowsForms . . . . . .


6

Оглавление
Приложения 163
165 169

IV

А. Примитивы библиотек GLU и GLUT Б. Демонстрационные программы

Б.1. Пример 1: Простое GLUT-приложение . . . . . . . Б.2. Пример 2: Модель освещения Op enGL . . . . . . . Б.3. Загрузка BMP файла . . . . . . . . . . . . . . . . . Б.4. Пример 3: Текстурирование и анимация . . . . . . Б.5. Класс для работы с Op enGL в Win32 . . . . . . . .
В. Примеры практических заданий

169 173 178 186 195
201

В.1. Cornell Box . . . . . . . . . . . . . . . . . . . . . . . В.2. Виртуальные часы . . . . . . . . . . . . . . . . . . . В.3. Интерактивный ландшафт . . . . . . . . . . . . . .
Литература Предметный указатель

201 204 206
215 217


Предисловие

Компьютерная (машинная) графика очень молодая дисциплина. Появление машинной графики как научно-исследовательского направления обычно связывают с именем Айвена Сазерленда (Ivan Sutherland), который в 1963 г. опубликовал статью с результатами своей диссертационной работы. В 1967 г. была образована профессиональная группа ACM SIGGRAPH. В ранний период развития машинной графики ассоциация SIGGRAPH развивалась как научно-техническая организация. В 1983 г. был сформирован Комитет SIGGRAPH по образованию для совершенствования обучения машинной графике и использования ее в учебном процессе. Мы стали свидетелями драматических изменений, которые произошли в компьютерной графике в 1990-е годы. Если в конце 80-х графические рабочие станции стоили безумно дорого и работать с ними могли только в очень богатых организациях (как правило из ВПК), то в конце 1990-х графические станции с вполне удовлетворительными возможностями за 1000 USD стали доступны университетам и даже отдельным студентам. Если в 1980-е использовалась преимущественно векторная графика, то в конце 1990-х растровая полноцветная графика почти полностью вытеснила векторную. Трехмерная графика стала столь же распространенной, как двухмерная, поскольку появились и быстро совершенствуются видеоплаты с графическими ускори7


8

Оглавление
Параллельно с изменениями графической аппаратуры про-

телями и z-буфером.

исходили глубокие метаморфозы в программном обеспечении. Вслед за широким распространением в 1970-е годы графических библиотек (в основном векторных, в большинстве своем фортранных) в 1980-е годы потребовалось несколько этапов стандартизации графического обеспечения (Core System, PHIGS, GKS), чтобы к середине 1990-х прийти к Открытой Графической Библиотеке (Op enGL). В настоящее время многие функции этой библиотеки реализованы аппаратно. Все эти процессы не могли не сказаться на преподавании компьютерной графики в университетах. Однако, даже в США до конца 1970-х годов машинная графика оставалась необычным предметом среди университетских курсов. В учебных планах ACM 1978 г. машинная графика отсутствовала. В 1980-е годы и в первой половине 1990-х целью курса было изучение и программирование базовых алгоритмов графики (рисование прямой и кривой, клиппирование, штриховка или растеризация многоугольника, однородные координаты и аффинные преобразования, видовые преобразования) [1, 2]. Теперь, при наличии интерфейса прикладного программирования (API) высокого уровня, когда элементарные функции имеются в библиотеке Op enGL и зачастую реализуются аппаратно, пришлось пересмотреть концепцию курса. В самом деле, зачем учиться умножать столбиком, если у каждого в руках калькулятор. Появилась возможность включить в курс более сложные и более современные разделы компьютерной графики, такие как текстурирование, анимация. Именно в соответствии с этой общемировой тенденцией эволюционировал курс компьютерной графики на факультете ВМиК МГУ (с 1999 г. интернет-версию курса можно найти на сайте http://courses.graphicon.ru). Следуя принципу "учись, делая"(learning-by-doing), мы, кроме традиционных лекций, включаем в курс выполнение 5-6 неболь-


Оглавление

9

ших проектов, каждый продолжительностью две недели. (Примеры таких заданий вы найдете в этой книге.) Настоящая книга призвана помочь студентам в выполнении этих проектов. В отличие от других справочных публикаций по Op enGL, в книге говориться не только о том, что имеется в библиотеке, но и о том, как этими средствами эффективно пользоваться. Например, как визуализировать зеркальные объекты, как построить тени. Моделируя реальную рабочую среду, мы учим студентов самостоятельной работе. В этих условиях пособие по использованию открытой графической библиотеки играет важную роль. Авторы благодарны Е. Костиковой и К. Каштановой за помощь в подготовке текста и иллюстраций. Ю.М. Баяковский Апрель 2007 года



Введение
Все, что мы видим на экране компьютерного монитора, является результатом работы алгоритмов синтеза изображений. Эти алгоритмы решают такие задачи, как визуализация текста с использованием заданного набор шрифтов, отображение указателя курсора, рисование вспомогательных элементов графического интерфейса, визуализацию изображений. Кроме этого, алгоритмы синтеза решают задачи визуализации трехмерных данных, например, с целью создания интерактивной фотореалистичной анимации, либо для наглядного представления результатов каких-либо вычислений. Для облегчения выполнения программистами таких задач еще в 80-х годах 20-го века стали появляться программные инструментарии (библиотеки), содержащие в себе наборы базовых алгоритмов (таких, как визуализация простых геометрических объектов), что позволило перейти на более высокий уровень абстракции при решении прикладных задач. В настоящее время программирование графических алгоритмов немыслимо без использования специальных программных инструментариев, также называемых прикладными программными интерфейсами (API Application Programming Interface). Op enGL является одним из самых популярных прикладных программных интерфейсов для разработки приложений в области двухмерной и трехмерной графики. 11


12

Оглавление
Стандарт Op enGL (Op en Graphics Library открытая гра-

фическая библиотека) был разработан и утвержден в 1992 году ведущими фирмами в области разработки программного обеспечения как эффективный аппаратно-независимый интерфейс, пригодный для реализации на различных платформах. Основой стандарта стала библиотека IRIS GL, разработанная фирмой Silicon Graphics Inc. Библиотека насчитывает около 120 различных команд, которые программист использует для задания объектов и операций, необходимых для написания интерактивных графических приложений. На сегодняшний день графическая система Op enGL поддерживается большинством производителей аппаратных и программных платформ. Эта система доступна тем, кто работает в среде Windows, пользователям компьютеров Apple. Свободно распространяемые коды системы Mesa (пакет API на базе Op enGL) можно компилировать в большинстве операционных систем, в том числе в Linux. Характерными особенностями Op enGL, которые обеспечили распространение и развитие этого графического стандарта, являются:

Стабильность

. Дополнения и изменения в стандарте реа-

лизуются таким образом, чтобы сохранить совместимость с разработанным ранее программным обеспечением.

Надежность и переносимость

. Приложения, использую-

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


Оглавление

13

Легкость применения

. Стандарт Op enGL имеет продуман-

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

Наличие хорошего базового пакета для работы с трехмерными приложениями упрощает понимание студентами ключевых тем курса компьютерной графики моделирование трехмерных объектов, закрашивание, текстурирование, анимацию и т.д. Широкие функциональные возможности Op enGL служат хорошим фундаментом для изложения теоретических и практических аспектов предмета. Книга состоит из трех частей и двух приложений. Первая часть посвящена непосредственно описанию работы с библиотекой, основным командам и переменным. Во второй части рассматриваются принципы реализации более сложных алгоритмов компьютерной графики с помощью средств Op enGL. В третьей части приводится описание настройки работы с Op enGL в различных интегрированных средах программирования и создание приложений, применяющих Op enGL для синтеза изображений. В приложениях можно найти демонстрационные программы на Op enGL и примеры практических заданий для самоконтроля. В пособии рассматривается стандарт Op enGL 1.2.



Часть I

Основы Op enGL

15



Глава 1.

Графический процесс и Op enGL
Прежде чем перейти к описанию функций Op enGL, необходимо понять ее место в процессе формирования изображения на экране, определить область, задачи которой можно решать с помощью библиотеки.

1.1. Графический процесс
Традиционной задачей компьютерной графики является синтез изображений объектов реального мира (как существующих, так и воображаемых). Для того, чтобы сделать такой синтез возможным, на входе алгоритма необходимы следующие данные:
Геометрические модели задают форму и внутреннюю струк-

туру объекта, обычно в трехмерном евклидовом пространстве. Примеры простых моделей:



сфера, заданная с помощью положения центра и радиуса; 17


18

Глава 1. Графический процесс и OPENGL



куб, заданный через положение центра и длины ребра.

Анимация служит для задания модели движения, изменения

формы или материала объекта с течением времени. Например, продольное перемещение объекта вдоль оси скоростью

x

со

s

м/c может быть задано с помощью формулы:

x(t) = st.
Материалы и текстуры определяют, как поверхность объек-

та взаимодействует со светом. Материалы необходимы для получения изображения объекта, с их помощью вычисляется количество отраженного света, попадающего в ?глаз? виртуального наблюдателя. Простейшая модель материала цвет объекта.
Освещение задает расположение и характеристики источников

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

дут отображаться (проецироваться) на двухмерное изображение. Заметим, что для задач, не требующих реалистичности получаемого изображения (например, научная визуализация), материалы могут сводиться к простейшим формам, например, к разным цветам объектов, а освещение отсутствовать. Далее в дело вступает алгоритм синтеза изображений, в описываемом частном случае называемый процессом (rendering). Имея на входе набор моделей, алгоритм должен построить соответствующее изображение на экране монитора. Описанная схема графической обработки от получения геометрической модели объекта до синтеза изображения на экране называется

экранизации

графическим процессом

.


1.2. Геометрические модели
оказывает в реализации графического процесса.

19

Остановимся более подробно на том, какую помощь Op enGL

Рис. 1.1. Графический процесс и место Op enGL в нем.

1.2. Геометрические модели
В компьютерной графике используется большое количество разнообразных моделей для описания формы. Причиной этого является очевидная невозможность полностью оцифровать реальный объект. Следовательно, необходимо выбирать те особенности объекта, которые важны для конкретной задачи и заданного класса объектов. В частности, модели можно поделить на объемные и граничные. Объемные модели позволяют описать внутренность объекта, а граничные геометрические свойства поверхности. Пример объемной модели показан на рисунке 1.2. В настоящее время наибольшую популярность завоевали граничные модели, получаемые с помощью локальной кусочнолинейной аппроксимации поверхности. Такая модель представляет собой набор связанных через общие вершины многоугольников (полигонов), поэтому эти модели еще называет

полигональ-


20

Глава 1. Графический процесс и OPENGL

Рис. 1.2. Объемная (воксельная) модель тора

ными

. Причина популярности полигональных моделей кроется

в их чрезвычайной гибкости и простоте, что позволило поддержать операции с такими моделями в графической аппаратуре. Пример граничной модели приведен на рисунке 1.3. Основным типом геометрических моделей, поддерживаемым Op enGL, являются как раз граничные полигональные модели. Отметим, что при этом библиотека не содержит каких-либо средств поддержки хранения данных на внешних носителях. Также в библиотеке нет средств для обработки и редактирования моделей единственной задачей Op enGL является реализация алгоритмов экранизации трехмерных моделей. Более подробно работа с моделями описана в главе 3.

1.3. Анимация
Анимация в настоящее время в основном задается вручную (в пакетах компьютерного моделирования), либо с помощью устройств сканирования движения (motion capture), позволяющих оцифровать перемещение объектов (например человека) или их частей (движения рук, ног, туловища). Op enGL содержит аппарат линейных преобразований, который используется в том числе для задания простой анимации


1.4. Материалы

21

Рис. 1.3. Граничная полигональная модель

(поворот, перенос, масштабирование). Более сложные технологии моделирования изменения формы и положения объектов (например, на основе кривых) могут быть реализованы ?поверх? библиотеки.

1.4. Материалы
Основными критериями выбора той или иной модели материала для поверхности объекта являются требования по реалистичности получаемого изображения и скорости работы алгоритма экранизации. Модель освещения применяется для каждого пикселя получаемого изображения, поэтому для задач, требующих интерактивного взаимодействия программы с пользователем, обычно выбираются простые модели. Op enGL изначально разрабатывалась как библиотека для программирования интерактивных графических приложений, в


22

Глава 1. Графический процесс и OPENGL

ней встроена одна из самых простых моделей материала модель Фонга. Также Op enGL поддерживает наложение текстур. В совокупности это позволяет добиваться достаточно реалистичной передачи свойств ?простых? материалов типа пластика, дерева и т.п. Подробно вопрос программирования материалов в Op enGL рассматривается в главе 5.

1.5. Освещение
Модель освещения неотделима от модели материала, поэтому принципы ее выбора определяются теми же требованиями. В реальном мире мы сталкиваемся с крайне сложными для моделирования условиями освещения протяженными источниками света (небо, люминесцентные лампы), вторичным освещением (освещением от отражающих поверхностей) и т.п. Стандарт Op enGL поддерживает точечные и параллельные источники света, цвет (мощность) которых задается в цветовой системе RGB (Red-Green-Blue). Не поддерживаются протяженные источники, спектральное задание мощности источников, вторичное освещение. Однако существуют алгоритмические приемы, позволяющие моделировать и эти эффекты с помощью возможностей Op enGL. Кроме этого, всегда возможно использовать качественные алгоритмы для просчета освещения и передавать Op enGL уже вычисленные цвета точек, что позволяет задействовать аппаратные возможности для обработки геометрии.

1.6. Виртуальная камера
Параметры виртуальной камеры определяют способ отображения трехмерных объектов в их двухмерное изображение. Существует достаточно большое количество разнообразных моделей камер, различающиеся свойствами проекции и учетом ха-


1.7. Алгоритм экранизации
ческого глаза).

23

рактеристик реальных оптических систем (фотокамер, человеВ Op enGL поддерживается достаточно широкий класс моделей камер, описываемый линейным преобразованием в однородных координатах [15]. Этот класс ограничен моделированием камер с бесконечно малым размером диафрагмы (нет возможности передачи глубины резкости) и линейными характеристиками проекции (нет возможности моделирования нелинейных искажений).

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

(x, y , z )

модели выполняется преобразование

T


(обычно линейное), такое, что

(xs , ys ) = T (x, y , z ),

где

(xs , ys )

координаты спроецированной точки на экране. В случае поли-


24

Глава 1. Графический процесс и OPENGL

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


Глава 2.

Введение в Op enGL

2.1. Основные возможности
Описывать возможности Op enGL мы будем через функции его библиотеки. Все функции можно разделить на пять категорий:

Функции описания примитивов
т.д.

определяют объекты ниж-

него уровня иерархии (примитивы), которые способна отображать графическая подсистема. В Op enGL в качестве примитивов выступают точки, линии, многоугольники и

Функции описания источников света Функции задания атрибутов
женных в трехмерной сцене.

служат для описа-

ния положения и параметров источников света, располо-

. С помощью задания атри-

бутов программист определяет, как будут выглядеть на экране отображаемые объекты. Другими словами, если с помощью примитивов определяется, что появится на экране, то атрибуты определяют способ вывода на экран. 25


26

Глава 2. Введение в OPENGL
В качестве атрибутов Op enGL позволяет задавать цвет, характеристики материала, текстуры, параметры освещения. позволяют задать положение на-

Функции визуализации

блюдателя в виртуальном пространстве, параметры объектива камеры. Зная эти параметры, система сможет не только правильно построить изображение, но и отсечь объекты, оказавшиеся вне поля зрения. Набор

функций геометрических преобразований

позволяет

программисту выполнять различные преобразования объектов поворот, перенос, масштабирование.

При этом Op enGL может выполнять дополнительные операции, такие как использование сплайнов для построения линий и поверхностей, удаление невидимых фрагментов изображений, работа с изображениями на уровне пикселей и т.д.

2.2. Интерфейс OpenGL
Op enGL состоит из набора библиотек. Все базовые функции хранятся в основной библиотеке, для обозначения которой в дальнейшем мы будем использовать аббревиатуру GL. Помимо основной, Op enGL включает в себя несколько дополнительных библиотек. Первая из них библиотека утилит GL(GLU GL Utility). Все функции этой библиотеки определены через базовые функции GL. В состав GLU вошла реализация более сложных функций, таких как набор популярных геометрических примитивов (куб, шар, цилиндр, диск), функции построения сплайнов, реализация дополнительных операций над матрицами и т.п. Op enGL не включает в себя никаких специальных команд для работы с окнами или ввода информации от пользователя. Поэтому были созданы специальные переносимые библиотеки


2.2. Интерфейс OPENGL

27

Рис. 2.1. Организация библиотеки Op enGL

для обеспечения часто используемых функций взаимодействия с пользователем и для отображения информации с помощью оконной подсистемы. Наиболее популярной является библиотека GLUT (GL Utility To olkit). Формально GLUT не входит в Op enGL, но de facto включается почти во все его дистрибутивы и имеет реализации для различных платформ. GLUT предоставляет только минимально необходимый набор функций для создания Op enGLприложения. Функционально аналогичная библиотека GLX менее популярна. В дальнейшем в этой книге в качестве основной будет рассматриваться GLUT. Кроме того, функции, специфичные для конкретной оконной подсистемы, обычно входят в ее прикладной программный интерфейс. Так, функции, поддерживающие выполнение Op enGL, есть в составе Win32 API и X Window. На рисунке 2.1 схематически представлена организация системы библиотек в версии, работающей под управлением системы Windows. Аналогичная организация используется и в других версиях Op enGL.


28

Глава 2. Введение в OPENGL

2.3. Архитектура OpenGL
Функции Op enGL реализованы в модели клиент-сервер. Приложение выступает в роли клиента оно вырабатывает команды, а сервер Op enGL интерпретирует и выполняет их. Сам сервер может находиться как на том же компьютере, на котором находится клиент (например, в виде динамически загружаемой библиотеки DLL), так и на другом (при этом может быть использован специальный протокол передачи данных между машинами). GL обрабатывает и рисует в буфере кадра графические примитивы с учетом некоторого числа выбранных режимов. Каждый примитив это точка, отрезок, многоугольник и т.д. Каждый режим может быть изменен независимо от других. Определение примитивов, выбор режимов и другие операции описываются с помощью команд в форме вызовов функций прикладной библиотеки. Примитивы определяются набором из одной или более вершин (vertex). Вершина определяет точку, конец отрезка или угол многоугольника. С каждой вершиной ассоциируются некоторые данные (координаты, цвет, нормаль, текстурные координаты и т.д.), называемые атрибутами. В подавляющем большинстве случаев каждая вершина обрабатывается независимо от других. С точки зрения архитектуры, графическая система Op enGL является конвейером, состоящим из нескольких последовательных этапов обработки графических данных. Команды Op enGL всегда обрабатываются в том порядке, в котором они поступают, хотя могут происходить задержки перед тем, как проявится эффект от их выполнения. В большинстве случаев Op enGL предоставляет непосредственный интерфейс, т.е. определение объекта вызывает его визуализацию в буфере кадра. С точки зрения разработчиков, Op enGL это набор команд,


2.3. Архитектура OPENGL

29

которые управляют использованием графической аппаратуры. Если аппаратура состоит только из адресуемого буфера кадра, тогда Op enGL должен быть реализован полностью с использованием ресурсов центрального процессора. Обычно графическая аппаратура предоставляет различные уровни ускорения: от аппаратной реализации вывода линий и многоугольников до изощренных графических процессоров с поддержкой различных операций над геометрическими данными.

Рис. 2.2. Функционирование конвейера Op enGL Op enGL является прослойкой между аппаратурой и пользовательским уровнем, что позволяет предоставлять единый интерфейс на разных платформах, используя возможности аппаратной поддержки. Кроме того, Op enGL можно рассматривать как конечный ав-


30

Глава 2. Введение в OPENGL

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

2.4. Синтаксис команд
Определения команд GL находятся в файле gl.h, для включения которого нужно написать

#i n c l u d e < g l / g l . h>
Для работы с библиотекой GLU нужно аналогично подключить файл glu.h. Версии этих библиотек, как правило, включаются в дистрибутивы систем программирования, например, Microsoft Visual C++ или Borland C++ Builder. В отличие от стандартных библиотек, пакет GLUT нужно инсталлировать и подключать отдельно. Подробная информация о настройке сред программирования для работы с Op enGL приведена в Части I I I. Все команды (процедуры и функции) библиотеки GL начинаются с префикса gl, все константы с префикса GL_. Соответствующие команды и константы библиотек GLU и GLUT аналогично имеют префиксы glu (GLU_) и glut (GLUT_) Кроме того, в имена команд входят суффиксы, несущие информацию о числе и типе передаваемых параметров. В Op enGL полное имя команды имеет вид:

t y p e glCommand_name [ 1 2 3 4 ] [ b s i f d ub u s u i ] [ v ] ( t y p e 1 a r g 1 ,. . ., t y p e N a r g N )
Имя состоит из нескольких частей:


2.5. Пример приложения
gl

31

имя библиотеки, в которой описана эта функция: для базовых функций Op enGL, функций из библиотек GL, GLU, GLUT, GLAUX это gl, glu, glut, aux соответственно;

Command_name

имя команды (процедуры или функции);

[1 2 3 4 ] число аргументов команды; [b s i f d ub us ui ] тип аргумента: символ b GLbyte (ана-

лог char в С/С++), символ i GLint (аналог int), символ f GLoat (аналог oat) и так далее. Полный список типов и их описание можно посмотреть в файле gl.h;
[v ] наличие этого символа показывает, что в качестве пара-

метров функции используется указатель на массив значений. Символы в квадратных скобках в некоторых названиях не используются. Например, команда команда

glVertex2i ()

описана в библио-

теке GL и использует в качестве параметров два целых числа, а

glColor3fv ()

использует в качестве параметра указатель

на массив из трех вещественных чисел. Использования нескольких вариантов каждой команды можно частично избежать, применяя перегрузку функций языка C++. Но интерфейс Op enGL не рассчитан на конкретный язык программирования, и, следовательно, должен быть максимально универсален.

2.5. Пример приложения
Типичная программа, использующая Op enGL, начинается с определения окна, в котором будет происходить отображение. Затем создается контекст (клиент) Op enGL и ассоциируется с этим окном. Далее программист может свободно использовать команды Op enGL API.


32

Глава 2. Введение в OPENGL
Ниже приведен текст небольшой программы, написанной с

использованием библиотеки GLUT своеобразный аналог классического примера ?Hello, World!?. Все, что делает эта программа рисует в центре окна красный квадрат. Тем не менее, даже на этом простом примере можно понять принципы программирования с помощью Op enGL. Программа 2.1. Простейший пример Op enGL.

#i n c l u d e < s t d l i b . h>

#i n c l u d e < g l / g l u t . h>

/ / п о д к л ю ч а е м б и б л и о т е к у GLUT / / н а ч а л ь н а я ширина и в ы с о т а о к н а

G L i n t Width = 5 1 2 , H e i g h t = 5 1 2 ;

// размер к у б а

const i n t C u b e S i z e = 2 0 0 ;

{

void D i s p l a y ( void )

/ / эта ф у н к ц и я у п р а в л я е т в с е м в ы в о д о м н а э к р а н

i n t l e f t , r i g h t , top , bottom ;
l e f t = ( Wid right = l e f t bottom = ( H e t o p = bottom th - +C ight +C CubeSize ) / 2 ; ubeSize ; - CubeSize ) / 2 ; ubeSize ;

glClearColor (0.7 , 0.7 , 0.7 , 1); g l C l e a r (GL_COLOR_BUFFER_BIT ) ; g g g g g g l l l l l l C B V V V V o e e e e e lor3ub ( 2 5 5 , 0 , 0 ) ; g i n (GL_QUADS ) ; r t e x 2 f ( l e f t , bottom ) ; r t e x 2 f ( l e f t , top ) ; r t e x 2 f ( r i g h t , top ) ; r t e x 2 f ( r i g h t , bottom ) ;


2.5. Пример приложения
glEnd ( ) ; } glFinish ();

33

{

void R e s h a p e ( GLint w , GLint h )
Width = w ; Height = h ;

/ / Функция в ы з ы в а е т с я п р и и з м е н е н и и р а з м е р о в о к н а

/ * у с т а н а в л и в а е м р а з м е р ы о б л а с т и отображения * /

g l V i e w p o r t ( 0 , 0 , w, h ) ;

/* ортографическая проекция */

g l M a t r i x M o d e (GL_PROJECTION ) ; glLoadIdentity ( ) ; glOrtho ( 0 , w, 0 , h , -1.0 , 1 . 0 ) ; g l M a t r i x M o d e (GL_MODELVIEW ) ; glLoadIdentity ( ) ;

}

{

void K e y b o a r d ( unsigned char k e y , i n t x , i n t y ) c o n s t c h a r ESCAPE = ' \ 0 3 3 ' ; i f ( k e y == ESCAPE )
exit (0);

/ / Функция о б р а б а т ы в а е т с о о б щ е н и я от к л а в и а т у р ы

}

{

void main ( i n t a r g c , char
g l u t I n i t (& a r g c , a r g v ) ;

/ / Г л а в н ы й ц и к л приложения * argv [ ] )


34

Глава 2. Введение в OPENGL
g l u t I n i t D i s p l a y M o d e (GLUT_RGB ) ; g l u t I n i t W i n d o w S i z e ( Width , H e i g h t ) ; g l u t C r e a t e W i n d o w ( " Red s q u a r e e x a m p l e " ) ; glutDisplayFunc ( Display ) ; glutReshapeFunc ( Reshape ) ; g l u t K e y b o a r d F u n c ( Keyboard ) ;

}

glutMainLoop ( ) ;

Рис. 2.3. Результат работы программы 2.1. Несмотря на малый размер, это полностью завершенная программа, которая должна компилироваться и работать на любой системе, поддерживающей Op enGL и GLUT. Библиотека GLUT поддерживает взаимодействие с пользователем с помощью так называемых функций c обратным вызовом (callback function). Если пользователь подвинул мышь, нажал на кнопку клавиатуры или изменил размеры окна, происходит событие и вызывается соответствующая функция пользователя обработчик событий (функция с обратным вызовом). Рассмотрим более подробно функцию

main

данного примера.


2.5. Пример приложения

35

Она состоит из трех частей: инициализации окна, в котором будет рисовать Op enGL, настройки функций c обратным вызовом и главного цикла обработки событий. Инициализация окна состоит из настройки соответствующих буферов кадра, начального положения и размеров окна, а также заголовка окна. Функция Команда RGB.

glutInit (&argc, argv)

производит начальную инициаинициализирует бу-

лизацию самой библиотеки GLUT.

glutInitDisplayMode(GLUT_RGB)

фер кадра и настраивает полноцветный (непалитровый) режим

glutInitWindowSize(Width, Height)
Наконец,

используется для задания назадает заго-

чальных размеров окна.

glutCreateWindow("Red square example")

ловок окна и визуализирует само окно на экране. Затем команды

glutDisplayFunc ( Display ) ; glutReshapeFunc ( Reshape ) ; g l u t K e y b o a r d F u n c ( Keyboard ) ;
регистрируют функции

Display(), Reshape() и Keyboard()

как функ-

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

glutMainLoop().

Заметим, что библиотека GLUT не входит в состав Op enGL, а является лишь переносимой прослойкой между Op enGL и оконной подсистемой, предоставляя минимальный интерфейс. Op enGL-приложение для конкретной платформы может быть написано с использованием специфических для платформы API (Win32, X Window и т.д.), которые как правило предоставляют более широкие возможности. Более подробно работа с библиотекой GLUT описана в главе 10.


36

Глава 2. Введение в OPENGL
Все вызовы команд Op enGL происходят в обработчиках со-

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

Display

, в которой

сосредоточен код, непосредственно отвечающий за рисование на

Display()

:

glClearColor (0 , 0 , 0 , 1); g l C l e a r (GL_COLOR_BUFFER_BIT ) ; glColor3ub ( 2 5 5 , 0 , 0 ) ; g l B e g i n (GL_QUADS ) ; g l V e r t e x 2 f ( l e f t , bottom ) ; g l V e r t e x 2 f ( l e f t , top ) ; g l V e r t e x 2 f ( r i g h t , top ) ; g l V e r t e x 2 f ( r i g h t , bottom ) ; glEnd ( ) ;
очищает окно и выводит на экран квадрат, задавая координаты четырех угловых вершин и цвет. В приложении Б приведен еще один пример несложной программы, при нажатии кнопку мыши рисующей на экране разноцветные случайные прямоугольники.

2.6. Контрольные вопросы
1) В чем, по вашему мнению, заключается необходимость создания стандартной графической библиотеки? 2) Кратко опишите архитектуру библиотек Op enGL и организацию конвейера. 3) В чем заключаются функции библиотек, подобных GLUT или GLX? Почему они формально не входят в Op enGL? 4) Назовите категории команд (функций) библиотеки.


2.6. Контрольные вопросы
ным автоматом?

37

5) Почему организацию Op enGL часто сравнивают с конеч-

6) Зачем нужны различные варианты команд Op enGL, отличающиеся только типами параметров? 7) Что можно сказать о количестве и типе параметров команды

glColor4ub()? glVertex3fv ()

?



Глава 3.

Рисование геометрических объектов

3.1. Процесс обновления изображения
Как правило, задачей программы, использующей Op enGL, является обработка трехмерной сцены и интерактивное отображение в буфере кадра. Сцена состоит из набора трехмерных объектов, источников света и виртуальной камеры, определяющей текущее положение наблюдателя. Обычно приложение Op enGL в бесконечном цикле вызывает функцию обновления изображения в окне. В этой функции и сосредоточены вызовы основных команд Op enGL. Если используется библиотека GLUT, то это будет функция с обратным вызовом, зарегистрированная с помощью вызова glutDisplayFunc(). GLUT вызывает эту функцию, когда операционная система информирует приложение о том, что содержимое окна необходимо перерисовать (например, если окно было перекрыто другим). Создаваемое изображение может быть как статичным, так и анимированным, т.е. зависеть от каких-либо параметров, изменяющихся со временем. В этом случае лучше вызывать функ39


40

Глава 3. Рисование геометрических объектов
glutPostRedisplay().
За более подробной информацией можно

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



очистка буферов Op enGL; установка положения наблюдателя; преобразование и рисование геометрических объектов.

Очистка буферов производится с помощью команды:

void g l C l e a r C o l o r ( c l a m p f r , c l a m p f g , c l a m p f b , void g l C l e a r ( b i t f i e l d b u f )
Команда

clampf a )

glClearColor

устанавливает цвет, которым будет за-

полнен буфер кадра. Первые три параметра команды задают R,G и B компоненты цвета и должны принадлежать отрезку

[0, 1].

Четвертый параметр задает так называемую альфа ком-

поненту (см. п. 7.1). Как правило, он равен 1. По умолчанию цвет черный (0,0,0,1). Команда

glClear

очищает буферы, а параметр buf определя-

ет комбинацию констант, соответствующую буферам, которые нужно очистить (см. главу 7). Типичная программа вызывает команду

g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
для очистки буферов цвета и глубины. Установка положения наблюдателя и преобразования трехмерных объектов (поворот, сдвиг и т.д.) контролируются с помощью задания матриц преобразования. Преобразования объектов и настройка положения виртуальной камеры описаны в главе 4.


3.2. Вершины и примитивы

41

Сейчас сосредоточимся на том, как передать в Op enGL описания объектов, находящихся в сцене. Каждый объект является набором примитивов Op enGL.

3.2. Вершины и примитивы
В Op enGL

вершина

(vertex) является атомарным графиче-

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

атрибуты.

В число

основных атрибутов входят положение вершины в пространстве,

3.2.1. Положение вершины в пространстве
Положение вершины определяются заданием ее координат в двух-, трех-, или четырехмерном пространстве (однородные координаты). Это реализуется с помощью нескольких вариантов команды

glVertex: void g l V e r t e x [ 2 3 4 ] [ s i f d ] ( t y p e c o o r d s ) void g l V e r t e x [ 2 3 4 ] [ s i f d ] v ( t y p e * c o o r d s ) glVertex2*

Каждая команда задает четыре координаты вершины: x, y, z, w. Команда получает значения x и y. Координата получает координаты x, y, z и z в таком случае устанавливается по умолчанию равной 0, координата w равной 1. все четыре координаты. Для ассоциации с вершинами цветов, нормалей и текстурных координат используются текущие значения соответствующих данных, что отвечает организации Op enGL как конечного

glVertex3*

заносит в координату w значение 1.

glVertex4*

позволяет задать


42

Глава 3. Рисование геометрических объектов

автомата. Эти значения могут быть изменены в любой момент с помощью вызова соответствующих команд.

3.2.2. Цвет вершины
Для задания текущего цвета вершины используются команды

v o i d g l C o l o r [ 3 4 ] [ b s i f ] ( GLtype c o m p o n e n t s ) v o i d g l C o l o r [ 3 4 ] [ b s i f ] v ( GLtype c o m p o n e n t s )
Первые три параметра задают R, G, B компоненты цвета, а последний параметр определяет коэффициент непрозрачности (так называемая альфа-компонента). Если в названии команды указан тип ?f? (oat), то значения всех параметров должны принадлежать отрезку [0,1], при этом по умолчанию значение альфа-компоненты устанавливается равным 1.0, что соответствует полной непрозрачности. Тип ?ub? (unsigned byte) подразумевает, что значения должны лежать в отрезке [0,255]. Вершинам можно назначать различные цвета, и, если включен соответствующий режим, то будет проводиться линейная интерполяция цветов по поверхности примитива. Для управления режимом интерполяции используется команда

v o i d g l S h a d e M o d e l ( GLenum mode )
вызов которой с параметром цию (установка по

GL_SMOOTH включает интерполяумолчанию), а с GL_FLAT отключает.

3.2.3. Нормаль
Определить нормаль в вершине можно, используя команды

void g l N o r m a l 3 [ b s i f d ] ( t y p e c o o r d s ) void g l N o r m a l 3 [ b s i f d ] v ( t y p e c o o r d s )


3.3. Операторные скобки GLBEGIN / GLEND

43

Для правильного расчета освещения необходимо, чтобы вектор нормали имел единичную длину. В Op enGL существует специальный режим, при котором задаваемые нормали будут нормироваться автоматически. Его можно включить командой

glEnable(GL_NORMALIZE)

.

Режим автоматической нормализации должен быть включен, если приложение использует модельные преобразования растяжения/сжатия, так как в этом случае длина нормалей изменяется при умножении на модельно-видовую матрицу. Однако применение этого режима уменьшает скорость работы механизма визуализации Op enGL, так как нормализация векторов имеет заметную вычислительную сложность (взятие квадратного корня). Поэтому лучше сразу задавать единичные нормали. Отметим, что команды

v o i d g l E n a b l e ( GLenum mode ) v o i d g l D i s a b l e ( GLenum mode )
производят включение и отключение того или иного режима работы конвейера Op enGL. Эти команды применяются достаточно часто, и их возможные параметры будут рассматриваться в каждом конкретном случае.

3.3. Операторные скобки glBegin / glEnd
Мы рассмотрели задание атрибутов одной вершины. Однако чтобы задать атрибуты графического примитива, одних координат вершин недостаточно. Эти вершины надо объединить в одно целое, определив необходимые свойства. Для этого в Op enGL используются так называемые операторные скобки, являющиеся вызовами специальных команд Op enGL. Определение примитива или последовательности примитивов происходит между вызовами команд


44

Глава 3. Рисование геометрических объектов

v o i d g l B e g i n ( GLenum mode ) void g l E n d ( void )
Параметр mo de определяет тип примитива, который задается внутри и может принимать следующие значения:
GL_POINTS

каждая вершина задает координаты некото-

рой точки.
GL_LINES

каждая отдельная пара вершин определяет от-

резок; если задано нечетное число вершин, то последняя вершина игнорируется.
GL_LINE_STRIP

каждая следующая вершина задает от-

резок вместе с предыдущей.
GL_LINE_LOOP

отличие от предыдущего примитива толь-

ко в том, что последний отрезок определяется последней и первой вершиной, образуя замкнутую ломаную.
GL_TRIANGLES

каждые отдельные три вершины опреде-

ляют треугольник; если задано не кратное трем число вершин, то последние вершины игнорируются.
GL_TRIANGLE_STRIP

каждая следующая вершина за-

дает треугольник вместе с двумя предыдущими.
GL_TRIANGLE_F AN

треугольники задаются первой вер-

шиной и каждой следующей парой вершин (пары не пересекаются).
GL_QUADS

каждая отдельная четверка вершин определя-

ет четырехугольник; если задано не кратное четырем число вершин, то последние вершины игнорируются.
GL_QUAD_STRIP

четырехугольник с номером n опреде-

ляется вершинами с номерами
GL_POLYGON

2n - 1, 2n, 2n + 2, 2n + 1
задаются вершины

. вы-

последовательно

пуклого многоугольника.


3.3. Операторные скобки GLBEGIN / GLEND
в вершинах, достаточно написать:

45

Например, чтобы нарисовать треугольник с разными цветами

GLfloat BlueCol [ 3 ] = { 0 , 0 , 1 } ; g g g g g g g g l B e g i n (GL_TRIANGLES lColor3f (1.0 , 0.0 , lVertex3f (0.0 , 0.0 , lColor3ub ( 0 , 2 5 5 , 0 ) ; lVertex3f (1.0 , 0.0 , l C o l o r 3 f v ( BlueCol ) ; lVertex3f (1.0 , 1.0 , lEnd ( ) ; ); 0 . 0 ) ; /* красный */ 0.0);
/* зеленый */ /* синий */

0.0);

0.0);

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

GL_TRIAGLE_FAN

GL_TRIANGLE_STRIP, GL_QUAD_STRIP

,

Кроме задания самих многоугольников, можно определить метод их отображения на экране. Однако сначала надо определить понятие лицевых и обратных граней. Под гранью понимается одна из сторон многоугольника, и по умолчанию лицевой считается та сторона, вершины которой обходятся против часовой стрелки. Направление обхода вершин лицевых граней можно изменить вызовом команды

v o i d g l F r o n t F a c e ( GLenum mode )
со значением параметра mo de равным clo ckwise). Чтобы изменить метод отображения многоугольника используется команда нуть значение по умолчанию можно, указав

GL_CW (clockwise), а верGL_CCW (counter-

v o i d g l P o l y g o n M o d e ( GLenum f a c e , Glenum mode )


46

Глава 3. Рисование геометрических объектов
Параметр

mode

определяет как будут отображаться много-

угольники, а параметр следующие значения:
GL_FRONT GL_BACK

face

устанавливает тип многоугольников,

к которым будет применяться эта команда и может принимать

для лицевых граней;

для обратных граней; для всех граней.

GL_FRONT_AND_BACK

Параметр
GL_POINT GL_LINE

mode

может быть равен:

отображение только вершин многоугольников;

многоугольники будут представляться набором

отрезков;
GL_FILL

многоугольники будут закрашиваться текущим

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

glEnable (GL_CULL_FACE)

, а затем вы-

брать тип отображаемых граней с помощью команды

v o i d g l C u l l F a c e ( GLenum mode )
Вызов с параметром

GL_FRONT

приводит к удалению из

изображения всех лицевых граней, а с параметром обратных (установка по умолчанию).

GL_BACK



Кроме рассмотренных стандартных примитивов в библиотеках GLU и GLUT описаны более сложные фигуры, такие как сфера, цилиндр, диск (в GLU) и сфера, куб, конус, тор, тетраэдр, додекаэдр, икосаэдр, октаэдр и чайник (в GLUT). Автоматическое наложение текстуры предусмотрено только для фигур из библиотеки GLU (создание текстур в Op enGL будет рассматриваться в главе 6).


3.4. Дисплейные списки
ла создать объект специального типа команды

47

Например, чтобы нарисовать сферу или цилиндр, надо снача-

GLUquadricOb j

с помощью

GLUquadricObj * g l u N e w Q u a d r i c ( void ) ;
а затем вызвать соответствующую команду:

void g l u S p h e r e ( GLUquadricObj

GLdouble r a d i u s , GLint s l i c e s , GLint s t a c k s ) G G G G G L L L L L dou dou dou int int bl bl bl s s e e e l t

* qobj ,

void g l u C y l i n d e r ( GLUquadricObj

* qobj , baseRadius , topRadius , height , ices , acks )

где параметр

stacks

slices

задает количество разбиений вокруг оси z, а

вдоль оси z.

Более подробную информацию об этих и других командах построения примитивов можно найти в приложении А.

3.4. Дисплейные списки
Если мы несколько раз обращаемся к одной и той же группе команд, то их можно объединить в так называемый дисплейный список (display list) и вызывать его при необходимости. Для того, чтобы создать новый дисплейный список, надо поместить все команды, которые должны в него войти, между следующими операторными скобками:

v o i d g l N e w L i s t ( G L u i n t l i s t , GLenum mode ) void g l E n d L i s t ( )


48

Глава 3. Рисование геометрических объектов
Для различения списков используются целые положитель-

ные числа, задаваемые при создании списка значением параметра

list

. Параметр

mode

определяет режим обработки команд,

входящих в список:
GL_COMPILE

команды записываются в список без выпол-

нения;
GL_COMPILE_AND_EXECUTE

команды выполняют-

ся, а затем записываются в список. После того, как список создан, его можно вызвать командой

void g l C a l l L i s t ( GLuint l i s t )
указав в параметре list идентификатор нужного списка. Чтобы вызвать сразу несколько списков, можно воспользоваться командой

void g l C a l l L i s t s ( c o n s t GLvoid

G L s i z e i n , GLenum t y p e , *lists )

вызывающей n списков с идентификаторами из массива lists, тип элементов которого указывается в параметре typ e. Это могут быть типы

GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_UNSIGNED_INT и некоторые другие. Для удаления списков используется команда

void g l D e l e t e L i s t s ( GLint l i s t , G L s i z e i r a n g e )
которая удаляет списки с идентификаторами ID из диапазона

list I D list + rang e - 1
Пример:

.

glNewLi glBeg glV glV glV

st in er er er

( 1 , GL_COMPILE ) ; (GL_TRIANGLES ) ; tex3f (1.0 f , 1.0 f , 1.0 f ) ; tex3f (10.0 f , 1.0 f , 1.0 f ) ; tex3f (10.0 f , 10.0 f , 1.0 f ) ;


3.5. Массивы вершин
glEnd ( ) ; glEndList () ... glCallList (1);

49

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

3.5. Массивы вершин
Если вершин много, то, чтобы не вызывать для каждой команду

glVertex,

удобно объединять вершины в массивы, исполь-

зуя команду

v o i d g l V e r t e x P o i n t e r ( G L i n t s i z e , GLenum t y p e , G L s i z e i s t r i d e , void * p t r )
которая определяет способ хранения и координаты вершин. При этом size определяет число координат вершины (может быть равен 2, 3, 4), typ e определяет тип данных (может быть равен

GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE).

Иногда удобно

хранить в одном массиве другие атрибуты вершины, тогда параметр stride задает смещение от координат одной вершины до координат следующей; если stride равен нулю, это значит, что координаты расположены последовательно. В параметре ptr указывается адрес, где находятся данные. Аналогично можно определить массив нормалей, цветов и некоторых других атрибутов вершины, используя команды

v o i d g l N o r m a l P o i n t e r ( GLenum t y p e , G L s i z e i s t r i d e ,


50

Глава 3. Рисование геометрических объектов

void * p o i n t e r ) v o i d g l C o l o r P o i n t e r ( G L i n t s i z e , GLenum t y p e , G L s i z e i s t r i d e , void * p o i n t e r )
Для того, чтобы эти массивы можно было использовать в дальнейшем, надо вызвать команду

void

g l E n a b l e C l i e n t S t a t e ( GLenum a r r a y )

с параметрами GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY соответственно. После окончания работы с массивом желательно вызвать команду

v o i d g l D i s a b l e C l i e n t S t a t e ( GLenum a r r a y )
с соответствующим значением параметра манда

array

.

Для отображения содержимого массивов используется ко-

void g l A r r a y E l e m e n t ( GLint i n d e x )
которая передает Op enGL атрибуты вершины, используя элементы массива с номером index. Это аналогично последовательному применению команд вида вается команда

glColor, glNormal, glVertex

c соот-

ветствующими параметрами. Однако вместо нее обычно вызы-

v o i d g l D r a w A r r a y s ( GLenum mode , G L i n t f i r s t ,
GLsizei count )
рисующая

count

примитивов, определяемых параметром

mode,

используя элементы из массивов с индексами от

f irst

до

f irst +

count - 1

glArrayElement()

. Это эквивалентно вызову последовательности команд с соответствующими индексами.

В случае, если одна вершина входит в несколько примитивов, вместо дублирования ее координат в массиве удобно использовать ее индекс. Для этого надо вызвать команду


3.6. Контрольные вопросы
v o i d g l D r a w E l e m e n t s ( GLenum mode , G L s i z e i c o u n t , GLenum t y p e , v o i d * i n d i c e s )

51

type опредеGL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, а count задает их
до использовать тип для построения примитивов, ляет элементов этого массива: количество. Важно отметить, что использование массивов вершин поз-

где

indices

это

массив

номеров

вершин,

которые

на-

воляет оптимизировать передачу данных на сервер Op enGL, и, как следствие, повысить скорость рисования трехмерной сцены. Такой метод определения примитивов является одним из самых быстрых и хорошо подходит для визуализации больших объемов данных.

3.6. Контрольные вопросы
1) Что такое функция обратного вызова и как функции обратного вызова могут быть использованы для работы с Op enGL? 2) Для чего нужна функция обновления изображения и что она делает? 3) Что такое примитив в Op enGL? 4) Что такое атрибут? Перечислите известные вам атрибуты вершин в Op enGL. 5) Что в Op enGL является атомарным примитивом? Какие типы примитивов вы знаете? 6) Для чего в Op enGL используются команды

glDisable

glEnable

и

?


52

Глава 3. Рисование геометрических объектов
7) Что такое операторные скобки и для чего они используются в Op enGL? 8) Что такое дисплейные списки? Как определить список и как вызвать его отображение? 9) Поясните организацию работы с массивами вершин и их отличие от дисплейных списков.

10) Поясните работу команды

glDrawElements().


3.6. Контрольные вопросы

53

Рис. 3.1. Примитивы Op enGL.



Глава 4.

Преобразования объектов

В Op enGL используются как основные три системы координат: левосторонняя, правосторонняя и оконная. Первые две системы являются трехмерными и отличаются друг от друга направлением оси z: в правосторонней она направлена на наблюдателя, в левосторонней в глубину экрана. Ось x направлена вправо относительно наблюдателя, ось y вверх. Левосторонняя система используется для задания значений параметрам команды

gluPerspective () , glOrtho(),

которые будут

рассмотрены в пункте 4.3. Правосторонняя система координат используется во всех остальных случаях. Отображение трехмерной информации происходит в двухмерную оконную систему координат. Строго говоря, Op enGL позволяет путем манипуляций с матрицами моделировать как правую, так и левую систему координат. Но на данном этапе лучше пойти простым путем и запомнить: основной системой координат Op enGL является правосторонняя система. 55


56

Глава 4. Преобразования объектов

(а)

(б)

(в)

Рис. 4.1. Системы координат в Op enGL. (а) правосторонняя, (б) левосторонняя, (в) оконная.

4.1. Работа с матрицами
Для задания различных преобразований объектов сцены в Op enGL используются операции над матрицами, при этом различают три типа матриц: модельно-видовая, матрица проекций и матрица текстуры. Все они имеют размер 4 4. Видовая матрица определяет преобразования объекта в мировых координатах, такие как параллельный перенос, изменение масштаба и поворот. Матрица проекций определяет, как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты), а матрица текстуры определяет наложение текстуры на объект. Умножение координат на матрицы происходит в момент вызова соответствующей команды Op enGL, определяющей координату (как правило, это команда пользуется команда:

Ц

glVertex.)

Для того чтобы выбрать, какую матрицу надо изменить, ис-

v o i d g l M a t r i x M o d e ( GLenum mode )
вызов

GL_MODELVIEW, GL_PROJECTION

которой

со

значением

параметра или

mode, равным GL_TEXTURE, вклю-

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


4.1. Работа с матрицами
сначала установить соответствующий режим.

57

Для определения элементов матрицы текущего типа вызывается команда

v o i d g l L o a d M a t r i x [ f d ] ( G L t y p e *m)
где

m

указывает на массив из 16 элементов типа

oat

или

double
m

в соответствии с названием команды, при этом сначала в нем должен быть записан первый столбец матрицы, затем второй, третий и четвертый. Еще раз обратим внимание: в массиве матрица записана по столбцам. Команда

void

g l L o a d I d e n t i t y ( void )

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

void g l P u s h M a t r i x ( void ) void g l P o p M a t r i x ( void )
Они записывают и восстанавливают текущую матрицу из стека, причем для каждого типа матриц стек свой. Для модельновидовых матриц его глубина равна как минимум 32, для остальных как минимум 2. Для умножения текущей матрицы на другую матрицу используется команда

v o i d g l M u l t M a t r i x [ f d ] ( G L t y p e *m)
где параметр

m

должен задавать матрицу размером 4

обозначить текущую матрицу за новится матрица

M

, передаваемую матрицу за

Ц

4. Если

T

то в результате выполнения команды

glMultMatrix

,

текущей ста-

M T

. Однако обычно для изменения матрицы

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


58

Глава 4. Преобразования объектов
В целом, для отображения трехмерных объектов сцены в ок-

но приложения используется последовательность, показанная на рисунке 4.2.

Рис. 4.2. Преобразования координат в Op enGL

Запомните: все преобразования объектов и камеры в Op enGL производятся с помощью умножения векторов координат на матрицы. Причем умножение происходит на текущую матрицу в момент определения координаты командой glVertex и некоторыми другими.

4.2. Модельно-видовые преобразования
К модельно-видовым преобразованиям будем относить перенос, поворот и изменение масштаба вдоль координатных осей. Для проведения этих операций достаточно умножить на соответствующую матрицу каждую вершину объекта и получить из-


4.2. Модельно-видовые преобразования
мененные координаты этой вершины:

59

x x y y =M z z 1 1
где

M

матрица модельно-видового преобразования. Перспек-

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

v o i d g l T r a n s l a t e [ f d ] ( GLtype x , GLtype y , GLtype z ) v o i d g l R o t a t e [ f d ] ( GLtype a n g l e , v o i d g l S c a l e [ f d ] ( GLtype x , GLtype y , GLtype z )
glTranslate glRotate glScale
натам его вершин значения своих параметров. производит поворот объекта против часовой стрелки на угол angle (измеряется в градусах) вокруг вектора растяжение) вдоль вектора

GLtype x , GLtype y , GLtype z )

производит перенос объекта, прибавляя к коорди-

(x , y , z)

.

производит масштабирование объекта (сжатие или

(x , y , z)

, умножая соответствующие

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

glRotate

glPushMatrix

, затем

с нужными параметрами, описать примитивы,

из которых состоит этот объект, а затем восстановить текущую матрицу командой

glPopMatrix

.

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


60

Глава 4. Преобразования объектов
GLdouble e y e x , GLdouble e y e y , GLdouble e y e z , GLdouble c e n t x , GLdouble c e n t y , GLdouble c e n t z , G L d o u b l e upx , G L d o u b l e upy , G L d o u b l e u p z )
точка

void g l u L o o k A t (

(ey ex, ey ey , ey ez ) определяет точку наблюдения, (centx, centy , centz ) задает центр сцены, который будет проецироваться в центр области вывода, а вектор (upx, upy , upz ) задает положительное направление оси y , определяя поворот камеры.
где Если, например, камеру не надо поворачивать, то задается значение

(0, 1, 0),

а со значением

(0, -1, 0)

сцена будет перевернута.

Строго говоря, эта команда совершает перенос и поворот объектов сцены, но в таком виде задавать параметры бывает удобнее. Следует отметить, что вызывать команду дельно-видовая матрица равна единичной. Запомните: матричные преобразования в Op enGL нужно записывать в обратном порядке. Например, если вы хотите сначала повернуть объект, а затем передвинуть его, сначала вызовите команду

gluLookAt()

имеет

смысл перед определением преобразований объектов, когда мо-

glTranslate ()

, а только потом

glRotate()

. После этого

определяйте сам объект.

4.3. Проекции
В Op enGL существуют стандартные команды для задания ортографической (параллельной) и перспективной проекций. Первый тип проекции может быть задан командами

void g l O r t h o ( GLdouble l e f t , GLdouble r i g h t ,

GLdouble bottom , GLdouble t o p , GLdouble n e a r , GLdouble f a r ) GLdouble bottom , GLdouble t o p )

void g l u O r t h o 2 D ( GLdouble l e f t , GLdouble r i g h t ,


4.3. Проекции

61

Первая команда создает матрицу проекции в усеченный объем видимости (параллелепипед видимости) в левосторонней системе координат. Параметры команды задают точки

(lef t, bottom, z near)

и

(rig ht, top, z f ar),

которые отвечают левому нижнему и право-

му верхнему углам окна вывода. Параметры лению от точки

near

и

far

задают

расстояние до ближней и дальней плоскостей отсечения по уда-

(0, 0, 0)

и могут быть отрицательными.

Рис. 4.3. Ортографическая проекция Во второй команде, в отличие от первой, значения устанавливаются равными

-1

и

1

near

и

far

соответственно. Это удобно,

если Op enGL используется для рисования двумерных объектов. В этом случае положение вершин можно задавать, используя команды

glVertex2.

Перспективная проекция определяется командой

void g l u P e r s p e c t i v e ( GLdouble a n g l e y , GLdouble a s p e c t ,
GLdouble z n e a r , GLdouble z f a r ) angley
которая задает усеченный конус видимости в левосторонней системе координат. Параметр определяет угол видимости в градусах по оси у и должен находиться в диапазоне от 0 до 180.


62

Глава 4. Преобразования объектов
aspect,
кото-

Угол видимости вдоль оси x задается параметром правило, размеров окна).

рый обычно задается как отношение сторон области вывода (как

Рис. 4.4. Перспективная проекция

Параметры

zfar

и

znear

задают расстояние от наблюдателя до

плоскостей отсечения по глубине и должны быть положительными. Чем больше отношение

z f ar/z near

, тем хуже в буфере глу-

бины будут различаться расположенные рядом поверхности, так как по умолчанию в него будет записываться ?сжатая? глубина в диапазоне от 0 до 1. Прежде те чем задавать матрицы с проекций, не забудь-

glMatrixMode(GL_PROJECTION) вызова glLoadIdentity().
Пример:

включить

режим

работы

нужной

матрицей

командой

и сбросить текущую с помощью

/* ортографическая проекция */

g l M a t r i x M o d e (GL_PROJECTION ) ; glLoadIdentity ( ) ; glOrtho ( 0 , w, 0 , h , -1.0 , 1 . 0 ) ;


4.4. Область вывода

63

4.4. Область вывода
После применения матрицы проекций на вход следующего преобразования подаются так называемые шин по формуле:

усеченные

(clipp ed)

координаты. Затем находятся нормализованные координаты вер-

xn xc /wc yn = yc /wc zn zc /wc
Область вывода представляет собой прямоугольник в оконной системе координат, размеры которого задаются командой

void g l V i e w P o r t ( GLint x , GLint y ,

GLint width , GLint h e i g h t )

Значения всех параметров задаются в пикселах и определяют ширину и высоту области вывода с координатами левого нижнего угла (x,y) в оконной системе координат. Размеры оконной системы координат определяются текущими размерами окна приложения, точка (0,0) находится в левом нижнем углу окна. Используя параметры команды мулам:

glViewPort()

, Op enGL вычис-

ляет оконные координаты центра области вывода (ox,oy) по фор-

ox = x + width/2 oy = y + heig ht/2
Пусть

px = width, py = heig ht

, тогда можно найти оконные

координаты каждой вершины:

xw (px /2)xn + ox yw = (py /2)yn + oy zw [(f - n)/2]zn + (n + f )/2
При этом целые положительные величины

n

и

f

задают ми-

нимальную и максимальную глубину точки в окне и по умолчанию равны 0 и 1 соответственно. Глубина каждой точки записывается в специальный буфер глубины (z-буфер), который


64

Глава 4. Преобразования объектов
n
и

используется для удаления невидимых линий и поверхностей. Установить значения

f

можно вызовом функции

v o i d g l D e p t h R a n g e ( GLclampd n , GLclampd f )
Команда

glViewPort()

обычно используется в функции, заре-

гистрированной с помощью команды жения.

glutReshapeFunc(),

которая

вызывается, если пользователь изменяет размеры окна прило-

4.5. Контрольные вопросы
1) Какие системы координат используются в Op enGL? 2) Перечислите виды матричных преобразований в Op enGL. Каким образом в Op enGL происходят преобразования объектов? 3) Что такое матричный стек? 4) Перечислите способы изменения положения наблюдателя в Op enGL. 5) Какая последовательность вызовов команд

glRotate() и glScale () соответствует команде gluLookAt(0, 0, -10, 10, 0, 0, 0, -1, 0)?
ете?

glTranslate ()

,

6) Какие стандартные команды для задания проекций вы зна-

7) Что такое видовые координаты? Нормализованные координаты?


Глава 5.

Материалы и освещение
Для создания реалистичных изображений необходимо определить как свойства самого объекта, так и свойства среды, в которой он находится. Первая группа свойств включает в себя параметры материала, из которого сделан объект, способы нанесения текстуры на его поверхность, степень прозрачности объекта. Ко второй группе можно отнести количество и свойства источников света, уровень прозрачности среды, а также модель освещения. Все эти свойства можно задавать, вызывая соответствующие команды Op enGL.

5.1. Модель освещения
В Op enGL используется модель освещения, в соответствии с которой цвет точки определяется несколькими факторами: свойствами материала и текстуры, величиной нормали в этой точке, а также положением источника света и наблюдателя. Для корректного расчета освещенности в точке надо использовать единичные нормали, однако команды типа

glScale

могут изменять

длину нормалей. Чтобы это учитывать, используйте уже упоминавшийся режим нормализации векторов нормалей, который 65


66

Глава 5. Материалы и освещение

включается вызовом команды

g l E n a b l e (GL_NORMALIZE)
Для задания глобальных параметров освещения используются команды

v o i d g l L i g h t M o d e l [ i f ] ( GLenum pname , GLenum param ) v o i d g l L i g h t M o d e l [ i f ] v ( GLenum pname , c o n s t GLtype * p a r a m s )
Аргумент pname определяет, какой параметр модели освещения будет настраиваться и может принимать следующие значения:
GL_LIGHT_MODEL_LOCAL_VIEWER

param

параметр

должен быть булевым и задает положение наблюда-

теля. Если он равен

GL_FALSE,
-z

то направление обзора счи-

тается параллельным оси

вне зависимости от положе-

ния в видовыx координатах. Если же он равен

GL_TRUE

,

то наблюдатель находится в начале видовой системы координат. Это может улучшить качество освещения, но усложняет его расчет. Значение по умолчанию:

GL_FALSE.
параметр

GL_LIGHT_MODEL_TWO_SIDE

param

дол-

жен быть булевым и управляет режимом расчета освещенности как для лицевых, так и для обратных граней. Если он равен

GL_FALSE,

то освещенность рассчитывается только

для лицевых граней. Если же он равен проводится и для обратных граней. Значение по умолчанию:

GL_TRUE

, расчет

GL_FALSE.
параметр

GL_LIGHT_MODE_AMBIENT

params

дол-

жен содержать четыре целых или вещественных числа, которые определяют цвет фонового освещения даже в случае отсутствия определенных источников света. Значение по умолчанию: (0.2, 0.2, 0.2,1.0).


5.2. Спецификация материалов

67

5.2. Спецификация материалов
Для задания параметров текущего материала используются команды

v o i d g l M a t e r i a l [ i f ] ( GLenum f a c e , GLenum pname , v o i d g l M a t e r i a l [ i f ] v ( GLenum f a c e , GLenum pname ,
GLtype * p a r a m s )
С их помощью можно определить рассеянный, диффузный и зеркальный цвета материала, а также степень зеркального отражения и интенсивность излучения света, если объект должен светиться. Какой именно параметр будет определяться значением

GLtype param )

param,

зависит от значения параметр

pname

: должен содержать четыре

GL_AMBIENT

params

целых или вещественных значения цветов RGBA, которые определяют рассеянный цвет материала (цвет материала в тени). Значение по умолчанию:
GL_DIFFUSE

(0.2, 0.2, 0.2, 1.0).

параметр

params

должен содержать четыре

целых или вещественных значения цветов RGBA, которые определяют диффузный цвет материала. Значение по умолчанию:
GL_SPECULAR

(0.8, 0.8, 0.8, 1.0).

параметр

params

должен содержать четы-

ре целых или вещественных значения цветов RGBA, которые определяют зеркальный цвет материала. Значение по умолчанию:
GL_SHININESS

(0.0, 0.0, 0.0, 1.0).

параметр

params

должен содержать одно

целое или вещественное значение в диапазоне от 0 до 128, которое определяет степень зеркального отражения материала. Значение по умолчанию:

0

.


68

Глава 5. Материалы и освещение
параметр

GL_EMISSION

params

должен содержать четыре

целых или вещественных значения цветов RGBA, которые определяют интенсивность излучаемого света материала. Значение по умолчанию:

(0.0, 0.0, 0.0, 1.0).
эквивалентно

GL_AMBIENT_AND_DIFFUSE

двум вызовам команды

GL_AMBIENT params.

и

glMaterial () со значением pname GL_DIFFUSE и одинаковыми значениями glMaterial [ i f ]()
возмо-

Из этого следует, что вызов команды териала (shininess). Команда Параметр

жен только для установки степени зеркального отражения ма-

glMaterial [ i f ] v()

используется для

задания остальных параметров.

face

определяет тип граней, для которых зада-

ется этот материал и может принимать значения

GL_BACK

или

GL_FRONT_AND_BACK.

GL_FRONT

,

Если в сцене материалы объектов различаются лишь одним параметром, рекомендуется сначала установить нужный режим, вызвав

glEnable()

c параметром

GL_COLOR_MATERIAL,

а затем

использовать команду

v o i d g l C o l o r M a t e r i a l ( GLenum f a c e , GLenum pname )
где параметр

face

имеет аналогичный смысл, а параметр

pname

может принимать все перечисленные значения. После этого значения выбранного с помощью манды кой

pname

свойства материала для кон-

кретного объекта (или вершины) устанавливаются вызовом ко-

glColor, что позволяет избежать вызовов более ресурсоемкоманды glMaterial и повышает эффективность программы.

Другие методы оптимизации приведены в главе 9. Пример определения свойств материала:

f l o a t mat_dif [ ] = { 0 . 8 , 0 . 8 , 0 . 8 } ; f l o a t mat_amb [ ] = { 0 . 2 , 0 . 2 , 0 . 2 } ; f l o a t mat_spec [ ] = { 0 . 6 , 0 . 6 , 0 . 6 } ;


5.3. Описание источников света
float shininess = 0.7 * 128; ... g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_AMBIENT, mat_amb ) ; g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_DIFFUSE , mat_dif ) ; g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec ) ; g l M a t e r i a l f (GL_FRONT, GL_SHININESS , shininess );

69

5.3. Описание источников света
Определение свойств материала объекта имеет смысл, только если в сцене есть источники света. Иначе все объекты будут черными (или, строго говоря, иметь цвет, равный рассеянному цвету материала, умноженному на интенсивность глобального фонового освещения, см. команду

glLightModel

). Добавить в сце-

ну источник света можно с помощью команд

v o i d g l L i g h t [ i f ] ( GLenum l i g h t , GLenum pname , v o i d g l L i g h t [ i f ] ( GLenum l i g h t , GLenum pname ,
G L f l o a t * params )
Параметр вида ми. Параметры манде

G L f l o a t param )

light

однозначно

определяет

источник

света.

Он выбирается из набора специальных символических имен станты

GL_LIGHTi, где i должно лежать в диапазоне от 0 до конGL_MAX_LIGHT, которая обычно не превосходит восьglMaterial pname
и

params

имеют смысл, аналогичный ко-

. Рассмотрим значения параметра параметр

pname

:

GL_SPOT_EXPONENT

param

должен содер-

жать целое или вещественное число от 0 до 128, задающее


70

Глава 5. Материалы и освещение
распределение интенсивности света. Этот параметр описывает уровень сфокусированности источника света. Значение по умолчанию: 0 (рассеянный свет).

GL_SPOT_CUTOFF

параметр

param

должен содержать

целое или вещественное число между 0 и 90 или равное 180, которое определяет максимальный угол разброса света. Значение этого параметра есть половина угла в вершине конусовидного светового потока, создаваемого источником. Значение по умолчанию: 180 (рассеянный свет).
GL_AMBIENT

параметр

params

должен содержать четыре

целых или вещественных значения цветов RGBA, которые определяют цвет фонового освещения. Значение по умолчанию:
GL_DIFFUSE

(0.0, 0.0, 0.0, 1.0).

параметр

params

должен содержать четыре

целых или вещественных значения цветов RGBA, которые определяют цвет диффузного освещения. Значение по умолчанию: и

(1.0, 1.0, 1.0, 1.0)

для

GL_LIGHT0

(0.0, 0.0, 0.0, 1.0)

для остальных.

GL_SPECULAR

параметр

params

должен содержать четы-

ре целых или вещественных значения цветов RGBA, которые определяют цвет зеркального отражения. Значение по умолчанию: и

(1.0, 1.0, 1.0, 1.0)

для

GL_LIGHT0

(0.0, 0.0, 0.0, 1.0)

для остальных.

GL_POSITION

параметр

params

должен содержать четыре

целых или вещественных числа, которые определяют положение источника света. Если значение компоненты w равно 0.0, то источник считается бесконечно удаленным и при расчете освещенности учитывается только направление на точку

(x, y , z ),

в противном случае считается, что источник

расположен в точке

(x, y , z , w).

В первом случае ослабления


5.3. Описание источников света
ник считается бесконечно удаленным. Значение по умолчанию:
GL_SPOT_DIRECTION

71

света при удалении от источника не происходит, т.е. источ-

(0.0, 0.0, 1.0, 0.0).
параметр

params

должен

хра-

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

(0.0, 0.0, -1.0, 1.0).

Эта характеристика источника имеет смысл, если значение

GL_SPOT_CUTOFF
но по умолчанию).

отлично от 180 (которое, кстати, зада-

GL_CONSTANT_ATTENUATION , GL_LINEAR_ATTENUATION , GL_QUADRATIC_ATTENUATION

параметр

params

задает значение одного из трех коэффициентов, определяющих ослабление интенсивности света от источника. Допускаются только при удалении неотрицательные

значения. Если источник не является направленным (см.

GL_POSITION
сумме:

), то ослабление обратно пропорционально

attconstant + attlinear d + attq uadratic d
где d расстояние им равны между источником света

2

и с

освеи по-

щаемой

вершиной;

attconstant

,

attlinear

attq uadratic

мощью констант GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION и GL_QUADRATIC_ATTENUATION соответственно. По умолчанию эти параметры задаются тройкой фактически ослабления не происходит.

параметрам,

заданным

(1, 0, 0),

и


72

Глава 5. Материалы и освещение
При изменении положения источника света следует учиты-

вать следующий факт: в Op enGL источники света являются объектами, во многом такими же, как многоугольники и точки. На них распространяется основное правило обработки координат в Op enGL параметры, описывающее положение в пространстве, преобразуются текущей модельно-видовой матрицей в момент формирования объекта, т.е. в момент вызова соответствующих команд Op enGL. Таким образом, формируя источник света одновременно с объектом сцены или камерой, его можно привязать к этому объекту. Или, наоборот, сформировать стационарный источник света, который будет оставаться на месте, пока другие объекты перемещаются. Общее правило такое: eсли положение источника света задается командой

glLight

перед определением положения виртуаль-

ной камеры (например, командой что координаты

glLookAt()),

то будет считаться,

(0, 0, 0)

источника находится в точке наблюде-

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

glEnable(GL_LIGHTING), а затем glEnable(GL_LIGHTi).

включить нуж-

Еще раз обратим внимание на то, что при выключенном освещении цвет вершины равен текущему цвету, который задается командами

glColor.

При включенном освещении цвет вершины

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


5.4. Создание эффекта тумана
Текст программы, демонстрирующей основные

73

принципы

определения материалов и источников света, приведен в приложении Б.

5.4. Создание эффекта тумана
В завершение рассмотрим одну интересную и часто используемую возможность Op enGL создание эффекта тумана. Легкое затуманивание сцены создает реалистичный эффект, а иногда может и скрыть некоторые артефакты, которые появляются, когда в сцене присутствуют отдаленные объекты. Туман в Op enGL реализуется путем изменения цвета объектов в сцене в зависимости от их глубины, т.е. расстояния до точки наблюдения. Изменение цвета происходит либо для вершин примитивов, либо для каждого пикселя на этапе растеризации в зависимости от реализации Op enGL. Этим процессом можно частично управлять см. раздел 7. Для включения эффекта затуманивания необходимо вызвать команду

glEnable(GL_FOG)

.

Метод вычисления интенсивности тумана в вершине можно определить с помощью команд

v o i d g l F o g [ i f ] (enum pname , T param ) v o i d g l F o g [ i f ] v (enum pname , T p a r a m s )
Аргумент pname может принимать следующие значения:
GL_FOG_MODE

аргумент

param

определяет формулу, по

которой будет вычисляться интенсивность тумана в точке.

В этом случае
GL_EXP GL_EXP2

param

может принимать следующие значения:

интенсивность задается формулой

f = e(

-dz ) ; (dz )2 ;

интенсивность задается формулой

f = e-


74

Глава 5. Материалы и освещение
интенсивность вычисляется по формуле где

GL_LINEAR

f=

e - z /e - s,

z

расстояние от вершины, в которой вы-

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

d, e, s
:

pname

задаются с помощью следующих зна-

GL_FOG_DENSITY GL_FOG_START GL_FOG_END



param

определяет коээфициент

d



param

определяет коэффициент

s



param

определяет коэффициент

e.
, равного

GL_FOG_COLOR

Цвет тумана задается с помощью аргумента . В этом случае

params

pname

указатель на массив

из 4-х компонент цвета. Приведем пример использования этого эффекта:

GLfl glEn glFo glFo glFo glFo

o a g g g g

at FogColor [ 4 ] = { 0 . 5 , 0 . 5 , 0 . 5 , 1 } ; b l e (GL_FOG ) ; i (GL_FOG_MODE, GL_LINEAR ) ; f (GL_FOG_START, 2 0 . 0 ) ; f (GL_FOG_END, 1 0 0 . 0 ) ; f v (GL_FOG_COLOR, F o g C o l o r ) ;

5.5. Контрольные вопросы
1) Поясните разницу между локальными и бесконечно удаленными источниками света. 2) Для чего служит команда

glColorMaterial

?

3) Как задать положение источника света таким образом, чтобы он всегда находился в точке положения наблюдателя? 4) Как задать фиксированное положение источника света? Можно ли задавать положение источника относительно локальных координат объекта?


5.5. Контрольные вопросы
5) Как задать конусный источник света?

75

6) Если в сцене включено освещение, но нет источников света, какой цвет будут иметь объекты?



Глава 6.

Текстурирование
Под текстурой будем понимать изображение, которое надо определенным образом нанести на объект, например, для придания иллюзии рельефности поверхности. Для работы с текстурой следует выполнить следующую последовательность действий:



выбрать изображение и преобразовать его к нужному формату; передать изображение в Op enGL; определить, как текстура будет наноситься на объект и как она будет с ним взаимодействовать; связать текстуру с объектом.

6.1. Подготовка текстуры
Для использования текстуры необходимо сначала загрузить в память нужное изображение и передать его Op enGL. 77


78

Глава 6. Текстурирование
Считывание графических данных из файла и их преобразо-

вание можно проводить вручную. В приложении Б приведен исходный текст функции для загрузки изображения из файла в формате BMP. Можно также воспользоваться функцией, входящей в состав библиотеки GLAUX (для ее использования надо дополнительно подключить glaux.lib), которая сама проводит необходимые операции. Это функция

AUX_RGBImageRec* a u x D I B I m a g e L o a d ( c o n s t c h a r * f i l e )
где

le

название файла с расширением *.bmp или *.dib. Функ-

ция возвращает указатель на область памяти, где хранятся преобразованные данные. При создании образа текстуры в памяти следует учитывать указываемые требования. Во-первых, размеры текстуры, как по горизонтали, так и по вертикали должны представлять собой степени двойки. Это требование накладывается для компактного размещения текстуры в текстурной памяти и способствует ее эффективному использованию. Работать только с такими текстурами конечно неудобно, поэтому после загрузки их надо преобразовать. Изменение размеров текстуры можно провести с помощью команды

v o i d g l u S c a l e I m a g e ( GLenum f o r m a t , G L i n t w i d t h i n ,

GL h e i g h t i n , GLenum t y p e i n , const void * d a t a i n , GLint w i d t h o u t , G L i n t h e i g h t o u t , GLenum t y p e o u t , void * d a t a o u t )

В качестве значения параметра значение

GL_RGB

ния информации. мощью

format обычно используется GL_RGBA, определяющее формат хранеПараметры widthin, heightin , widhtout, heightout
или задается тип элементов массивов, распо-

определяют размеры входного и выходного изображений, а с по-

typein

и

typeout


6.1. Подготовка текстуры
ложенных по адресам жет быть тип

79

datain и dataout. Как и обычно, это GL_UNSIGNED_BYTE, GL_SHORT, GL_INT и dataout.

мот.д.

Результат своей работы функция заносит в область памяти, на которую указывает параметр Во-вторых, надо предусмотреть случай, когда объект после растеризации оказывается по размерам значительно меньше наносимой на него текстуры. Чем меньше объект, тем меньше должна быть наносимая на него текстура и поэтому вводится понятие уровней детализации текстуры (mipmap). Каждый уровень детализации задает некоторое изображение, которое является, как правило, уменьшенной в два раза копией оригинала. Такой подход позволяет улучшить качество нанесения текстуры на объект. Например, для изображения размером построить

2m Ч 2

n можно

max(m, n) + 1

уменьшенных изображений, соответ-

ствующих различным уровням детализации. Эти два этапа создания образа текстуры во внутренней памяти Op enGL можно провести с помощью команды

v o i d g l u B u i l d 2 D M i p m a p s ( GLenum t a r g e t ,

GLint components , GLint width , GLint h e i g h t , GLenum f o r m a t , GLenum t y p e , const void * d a t a )

где параметр раметр

target должен быть равен GL_TEXTURE_2D. Паcomponents определяет количество цветовых компонент
одна компонента яркость (текстура

текстуры и может принимать следующие основные значения:
GL_LUMINANCE

будет монохромной);
GL_RGB

красный, синий, зеленый; красный, синий, зеленый, альфа (см. п. 7.1).

GL_RGBA

Параметры

width, height, data

ложение текстуры соответственно, а гичный смысл, что и в команде

format и type gluScaleImage().

определяют размеры и распоимеют анало-


80

Глава 6. Текстурирование
После выполнения этой команды текстура копируется во

внутреннюю память Op enGL, и поэтому память, занимаемую исходным изображением, можно освободить. В Op enGL допускается использование одномерных текстур, то есть размера

1ЧN

, однако это всегда надо указывать, за-

давая в качестве значения

target

константу

GL_TEXTURE_1D.

Одномерные текстуры используются достаточно редко, поэтому не будем останавливаться на этом подробно. При использовании в сцене нескольких текстур, в Op enGL применяется подход, напоминающий создание списков изображений (так называемые текстурные объекты). Сначала с помощью команды

void g l G e n T e x t u r e s ( G L s i z e i n , GLuint
саны в массив

* textures )

надо создать n идентификаторов текстур, которые будут запи-

textures

. Перед началом определения свойств оче-

редной текстуры следует сделать ее текущей (?привязать? текстуру), вызвав команду

v o i d g l B i n d T e x t u r e ( GLenum t a r g e t , G L u i n t t e x t u r e )
где target может принимать значения

GL_TEXTURE_2D

, а параметр

texture

GL_TEXTURE_1D

или

должен быть равен иден-

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

target

и

texture

glBindTexture()

. Таким образом, команда

включает режим создания текстуры с

glBindTexture() идентификатором texture,

c соответствующим зна-

если такая текстура еще не создана, либо режим ее использования, то есть делает эту текстуру текущей. Так как не всякая аппаратура может оперировать текстурами большого размера, целесообразно ограничить размеры текстуры до

256 Ч 256

или

512 Ч 512

пикселей. Отметим, что использование

небольших текстур повышает эффективность программы.


6.2. Наложение текстуры на объекты

81

6.2. Наложение текстуры на объекты
При наложении текстуры, как уже упоминалось, надо учитывать случай, когда размеры текстуры отличаются от оконных размеров объекта, на который она накладывается. При этом возможно как растяжение, так и сжатие изображения, и то, как будут проводиться эти преобразования, может серьезно повлиять на качество построенного изображения. Для определения положения точки на текстуре используется параметрическая система координат

(s, t),

причем значения

s

и

t

находятся в отрезке

[0, 1]

(см. рисунок 6.1)

Рис. 6.1. Текстурные координаты Для изменения различных параметров текстуры применяются команды:

v o i d g l T e x P a r a m e t e r [ i f ] ( GLenum t a r g e t , GLenum pname , v o i d g l T e x P a r a m e t e r [ i f ] v ( GLenum t a r g e t , GLenum pname ,
Glenum * p a r a m s ) target принимает значения GL_TEXTURE_1D или GL_TEXTURE_2D, pname определяет, какое свойство будем менять, а с помощью param или params устанавливается новое значение. Возможные значения pname:
Параметр
GL_TEXTURE_MIN_FILTER

GLenum p a r a m )

параметр

param

опреде-


82

Глава 6. Текстурирование
ляет функцию, которая будет использоваться для сжатия текстуры. При значении ся один (ближайший), а

GL_NEAREST будет использоватьпри значении GL_LINEAR четыGL_LINEAR
.

ре ближайших элемента текстуры. Значение по умолчанию:

GL_TEXTURE_MAG_FILTER

параметр

param

опреде-

ляет функцию, которая будет использоваться для увеличения (растяжения) текстуры. При значении

GL_NEAREST

будет использоваться один (ближайший), а при значении

GL_LINEAR

четыре ближайших элемента текстуры.

Значение по умолчанию:

GL_LINEAR
s,

.

GL_TEXTURE_WRAP_S

параметр

param

устанавлива-

ет значение координаты

[0, 1].

При значении

GL_REPEAT

если оно не входит в отрезок целая часть

s

отбрасы-

вается, и в результате изображение размножается по поверхности. При значении

GL_CLAMP

используются крае-

вые значения (0 или 1), что удобно использовать, если на объект накладывается один образ. Значение по умолчанию:

GL_REPEAT.
аналогично предыдущему зна-

GL_TEXTURE_WRAP_T

чению, только для координаты Использование режима в отличие от

t

. повышает скорость на-

GL_NEAREST

ложения текстуры, однако при этом снижается качество, так как,

GL_LINEAR

, интерполяция не производится.

Для того чтобы определить, как текстура будет взаимодействовать с материалом, из которого сделан объект, используются команды

void glTexEnv [ i f ]

( GLenum GLtype v o i d g l T e x E n v [ i f ] v ( GLenum GLtype

t a r g e t , GLenum pname , param ) t a r g e t , GLenum pname , * params )


6.2. Наложение текстуры на объекты
Параметр а в качестве

83

target должен быть равен GL_TEXTURE_ENV, pname рассмотрим только одно значение GL_TEXTURE_ENV_MODE, которое применяется наиболее
часто. Наиболее часто используемые значения параметра
GL_MODULATE

param:

конечный цвет находится как произведе-

ние цвета точки на поверхности и цвета соответствующей ей точки на текстуре.
GL_REPLACE

в качестве конечного цвета используется

цвет точки на текстуре. Следующий пример кода демонстрирует общий подход к созданию текстур:

#d e f i n e NUM_TEXTURES 1 0

/ * нужное нам к о л и ч е с т в о текстур * / / * идентификаторы текстур * /

/ * о б р а з текстуры * / AUX_RGBImageRec * p I m a g e ;

i n t T e x t u r e I D s [ NUM_TEXTURES ] ;

...

/ * 1 ) п о л у ч а е м идентификаторы текстур * /

g l G e n T e x t u r e s (NUM_TEXTURES, T e x t u r e I D s ) ;

/ * 2 ) в ы б и р а е м текстуру д л я м о д и ф и к а ц и и п а р а м е т р о в * / g l B i n d T e x t u r e ( T e x t u r e I D s [ i ] ) ; / * 0<= i
p I m a g e=d i b I m a g e L o a d ( " t e x t u r e . bmp" ) ; {

i f ( T e x t u r e ! =NULL)
/ * 4 ) п е р е д а е м текстуру OpenGL и з а д а е м параметры * /


84

Глава 6. Текстурирование
/ * в ы р а в н и в а н и е п о байту * /

g l P i x e l S t o r e i (GL_UNPACK_ALIGNMENT, 1 ) ;

g l u B u i l d M i p m a p s (GL_TEXTURE_2D, GL_RGB, p I m a g e->s i z e X , p I m a g e->s i z e Y , GL_RGB, GL_UNSIGNED_BYTE, p I m a g e->d a t a ) ; g l T e x P a r a m e t e r f (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ( f l o a t ) GL_LINEAR ) ; g l T e x P a r a m e t e r f (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ( f l o a t ) GL_LINEAR ) ; g l T e x P a r a m e t e r f (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( f l o a t )GL_REPEAT ) ; g l T e x P a r a m e t e r f (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( f l o a t )GL_REPEAT ) ; g l T e x E n v f (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, ( f l o a t )GL_REPLACE ) ;
/* 5 ) удаляем и с х о д н о е изображение . */

f r e e ( Texture ) ;

}

else

Error ( ) ;

6.3. Текстурные координаты
Перед нанесением текстуры на объект необходимо установить соответствие между точками на поверхности объекта и на самой текстуре. Задавать это соответствие можно двумя методами: отдельно для каждой вершины или сразу для всех вершин, задав


6.3. Текстурные координаты
реализуется с помощью команд

85

параметры специальной функции отображения. Первый метод

void g l T e x C o o r d [ 1 2 3 4 ] [ s i f d ] ( t y p e c o o r d ) void g l T e x C o o r d [ 1 2 3 4 ] [ s i f d ] v ( t y p e * c o o r d )
Чаще всего используются команды

glTexCoord2*(type s, type t)

,

задающие текущие координаты текстуры. Понятие текущих координат текстуры аналогично понятиям текущего цвета и текущей нормали и является атрибутом вершины. Однако даже для куба нахождение соответствующих координат текстуры является довольно трудоемким занятием, поэтому в библиотеке GLU помимо команд, проводящих построение таких примитивов как сфера, цилиндр и диск, предусмотрено также наложение на них текстур. Для этого достаточно вызвать команду

void g l u Q u a d r i c T e x t u r e (
textureCoords

GLUquadricObj * q u a d O b j e c t , GLboolean t e x t u r e C o o r d s )
равным

с параметром

GL_TRUE

, и тогда текущая

текстура будет автоматически накладываться на примитив. Второй метод реализуется с помощью команд

( GLenum c o o r d GLtype param v o i d g l T e x G e n [ i f d ] v ( GLenum c o o r d c o n s t GLtype
Параметр

void glTexGen [ i f d ]

, GLenum pname , ) , GLenum pname , * params )
мо-

coord

определяет для какой координаты задается

формула, и может принимать значение

GL_S, GL_T; pname

жет быть равен одному из следующих значений:
GL_TEXTURE_GEN_MODE

задает функцию для на-

ложения текстуры. В этом случае аргумент param принимает значения:
GL_OBJECT_LINEAR

значение

соответствующей

текстурной координаты определяется расстоянием до


86

Глава 6. Текстурирование
GL_OBJECT_PLANE
следующим образом: плоскости, задаваемой с помощью значения

pname

(см. ниже). Формула выглядит

g = x xp + y yp + z zp + w wp
где или ки.

g соответствующая текстурная координата (s p), x, y , z , w координаты соответствующей точxp , yp , zp , wp коэффициенты уравнения плоско аналогично

сти. В формуле используются координаты объекта.
GL_EYE_LINEAR

GL_OBJECT_LINEAR,

только в формуле используются видовые координаты. Т.е. координаты текстуры объекта в этом случае зависят от положения этого объекта.
GL_SPHERE_MAP

позволяет эмулировать отраже-

ние от поверхности объекта. Текстура как бы ?оборачивается? вокруг объекта. Для данного метода используются видовые координаты и необходимо задание нормалей.
GL_OBJECT_PLANE

позволяет задать плоскость, рас-

стояние до которой будет использоваться при генерации координат, если установлен режим этом случае параметр

params

GL_OBJECT_LINEAR.

В

является указателем на мас-

сив из четырех коэффициентов уравнения плоскости.
GL_EYE_PLANE

аналогично предыдущему значению. Поз-

воляет задать плоскость для режима

GL_EYE_LINEAR

.

Для установки автоматического режима задания текстурных

GL_TEXTURE_GEN_S

координат необходимо вызвать команду или

glEnable с GL_TEXTURE_GEN_P

параметром .

Программа, использующая наложение текстуры и анимацию, приведена в приложении Б.


6.4. Контрольные вопросы

87

6.4. Контрольные вопросы
1) Что такое текстура и для чего используются текстуры? 2) Что такое текстурные координаты и как задать их для объекта? 3) Какой метод взаимодействия с материалом нужно использовать, если текстура представляет собой картину, висящую на стене (

GL_MODULATE, GL_REPLACE

)?

4) Перечислите известные вам методы генерации текстурных координат в Op enGL. 5) Для чего используются уровни детализации текстуры (mipmapping)? 6) Что такое режимы фильтрации текстуры и как задать их в Op enGL?



Глава 7.

Операции с пикселями
После проведения всех операций по преобразованию координат вершин, вычисления цвета и т.п., Op enGL переходит к этапу растеризации, на котором происходит растеризация всех примитивов, наложение текстуры, наложение эффекта тумана. Для каждого примитива результатом этого процесса является занимаемая им в буфере кадра область, каждому пикселю этой области приписывается цвет и значение глубины. Op enGL использует эту информацию, чтобы записать обновленные данные в буфер кадра. Для этого Op enGL имеет не только отдельный конвейер обработки пикселей, но и несколько дополнительных буферов различного назначения. Это позволяет программисту гибко контролировать процесс визуализации на самом низком уровне. Графическая библиотека Op enGL поддерживает работу со следующими буферами:



несколько буферов цвета; буфер глубины; буфер-накопитель (аккумулятор); 89


90

Глава 7. Операции с пикселями



буфер маски.

Группа буферов цвета включает буфер кадра, но таких буферов может быть несколько. При использовании двойной буферизации говорят о рабочем (front) и фоновом (back) буферах. Как правило, в фоновом буфере программа создает изображение, которое затем разом копируется в рабочий буфер. На экране может появиться информация только из буферов цвета. Буфер глубины используется для удаления невидимых поверхностей и прямая работа с ним требуется крайне редко. Буфер-накопитель можно применять для различных операций. Более подробно работа с ним описана в разделе 7.2. Буфер маски используется для формирования пиксельных масок (трафаретов), служащих для вырезания из общего массива тех пикселей, которые следует вывести на экран. Буфер маски и работа с ним более подробно рассмотрены в разделах 7.3, 8.2 и 8.3.

7.1. Смешивание изображений и прозрачность
Разнообразные прозрачные объекты стекла, прозрачная посуда и т.д. часто встречаются в реальности, поэтому важно уметь создавать такие объекты в интерактивной графике. Op enGL предоставляет программисту механизм работы с полупрозрачными объектами, который и будет кратко описан в этом разделе. Прозрачность реализуется с помощью специального режима смешивания цветов (blending). Алгоритм смешивания комбинирует цвета так называемых входящих пикселей (т.е. ?кандидатов? на помещение в буфер кадра) с цветами соответствующих пикселей, уже хранящихся в буфере. Для смешивания используется четвертая компонента цвета альфа-компонента,


7.1. Смешивание изображений и прозрачность

91

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

glEnable(GL_BLEND).
манды:

Определить параметры смешивания можно с помощью ко-

v o i d g l B l e n d F u n c (enum s r c , enum d s t )
Параметр циента

src

определяет как получить коэффициент

ходного цвета пикселя, a

dst

k1

ис-

задает способ получения коэффи-

k2

для цвета в буфере кадра. Для получения результи-

рующего цвета используется следующая формула:

res = csrc

k1 + cdst k2

, где

csr

c цвет исходного пикселя,

cdst

цвет пиксе-

ля в буфере кадра ( RGBA-векторы).

res, k1 , k1 , csr

c,

cdst

четырехкомпонентные

src

Приведем наиболее часто используемые значения агрументов и

dst

.

GL_SRC_ALPHA

k = (As , As , As , As )

GL_SRC_ONE_MINUS_ALPHA

k = (1, 1, 1, 1) - (As , As , As , As )
GL_DST_COLOR

k = (Rd , Gd , Bd )

GL_ONE_MINUS_DST_COLOR

k = (1, 1, 1, 1) - (Rd , Gd , Bd , d )
GL_DST_ALPHA

k = (Ad , A - d, A - d, Ad )

GL_DST_ONE_MINUS_ALPHA

k = (1, 1, 1, 1) - (Ad , Ad , Ad , Ad )


92

Глава 7. Операции с пикселями
k = (Rs, Gs, B s)

GL_SRC_COLOR

GL_ONE_MINUS_SRC_COLOR

k = (1, 1, 1, 1) - (Rs , Gs , Bs , As )
Пример: предположим, мы хотим реализовать вывод прозрачных объектов. Коэффициент прозрачности задается альфакомпонентой цвета. Пусть 1 непрозрачный объект; 0 абсолютно прозрачный, т.е. невидимый. Для реализации служит следующий код:

g l E n a b l e (GL_BLEND ) ; g l B l e n d F u n c (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
Например, полупрозрачный треугольник можно задать следующим образом:

glCol glBeg glV glV glV glEnd

or in er er er ()

3f (1.0 , 0.0 , 0 (GL_TRIANGLES ) tex3f (0.0 , 0.0 tex3f (1.0 , 0.0 tex3f (1.0 , 1.0 ;

. ; , , ,

0 , 0.5); 0.0); 0.0); 0.0);

Если в сцене есть несколько прозрачных объектов, которые могут перекрывать друг друга, корректный вывод можно гарантировать только в случае выполнения следующих условий:



все прозрачные объекты выводятся после непрозрачных; при выводе объекты с прозрачностью должны быть упорядочены по уменьшению глубины, т.е. выводиться, начиная с наиболее отдаленных от наблюдателя.

В Op enGL команды обрабатываются в порядке их поступления, поэтому для реализации перечисленных требований достаточно расставить в соответствующем порядке вызовы команд

glVertex,

но и это в общем случае нетривиально.


7.2. Буфер-накопитель

93

7.2. Буфер-накопитель
Буфер-накопитель (accumulation buer) это один из дополнительных буферов Op enGL. В нем можно сохранять визуализированное изображение, применяя при этом попиксельно специальные операции. Буфер-накопитель широко используется для создания различных спецэффектов. Изображение берется из буфера, выбранного на чтение командой

v o i d g l R e a d B u f f e r (enum b u f )
buf определяет буфер для чтения. Значения buf, равные GL_BACK, GL_FRONT, определяют соответствующие буферы цвета для чтения. GL_BACK задает в качестве источника пикселей внеэкранный буфер; GL_FRONT текущее содерАргумент жимое окна вывода. Команда имеет значение, если используется дублирующая буферизация. В противном случае используется только один буфер, соответствующий окну вывода (строго говоря, Op enGL имеет набор дополнительных буферов, используемых, в частности, для работы со стереоизображениями, но здесь мы их рассматривать не будем). Буфер-накопитель является дополнительным буфером цвета. Он не используется непосредственно для вывода образов, но они добавляются в него после вывода в один из буферов цвета. Применяя различные операции, описанные ниже, можно понемногу ?накапливать? изображение в буфере. Затем полученное изображение переносится из буфера-накопителя в один из буферов цвета, выбранный на запись командой

v o i d g l D r a w B u f f e r (enum b u f )
Значение

buf

мента в команде мандой

glReadBuer

аналогично значению соответствующего аргу.

Все операции с буфером-накопителем контролируются ко-


94

Глава 7. Операции с пикселями
Аргумент

v o i d g l A c c u m (enum op , G L f l o a t v a l u e )
op
задает операцию над пикселями и может принимать следующие значения:
GL_LOAD

пиксель берется из буфера, выбранного на чте-

ние, его значение умножается на value и заносится в буфернакопитель;
GL_ACCUM

аналогично предыдущему, но полученное по-

сле умножения значение складывается с уже имеющимся в буфере;
GL_MULT

эта операция умножает значение каждого пик-

селя в буфере накопления на value;
GL_ADD

аналогично предыдущему, только вместо умноже-

ния используется сложение;
GL_RETURN

Изображение переносится из буфера нако-

пителя в буфер, выбранный для записи. Перед этим значение каждого пикселя умножается на value.

Следует отметить, что для использования буфера-накопителя нет необходимости вызывать какие-либо команды Достаточно инициализировать только сам буфер. Пример использования буфера-накопителя для устранения погрешностей растеризации (ступенчатости) приведен в разделе 8.1.

glEnable.

7.3. Буфер маски
При выводе пикселей в буфер кадра иногда возникает необходимость выводить не все пиксели, а только некоторое подмножество, т.е. наложить трафарет (маску) на изображение. Для этого Op enGL предоставляет так называемый буфер маски (stencil


7.3. Буфер маски
несколько интересных возможностей.

95

buer). Кроме наложения маски, этот буфер предоставляет еще Прежде чем поместить пиксель в буфер кадра, механизм визуализации Op enGL позволяет выполнить сравнение (тест) между заданным значением и значением в буфере маски. Если тест проходит, пиксель рисуется в буфере кадра. Механизм сравнения весьма гибок и контролируется следующими командами:

v o i d g l S t e n c i l F u n c (enum f u n c , i n t r e f , u i n t mask ) v o i d g l S t e n c i l O p (enum s f a i l , enum d p f a i l , enum d p p a s s )
Аргумент

ref

команды

glStencilFunc func

задает значение для срав-

нения. Он должен принимать значение от 0 до число бит на точку в буфере маски. С помощью аргумента

2s - 1,

где

s



задается функция сравнения. Он

может принимать следующие значения:
GL_NEVER

тест никогда не проходит, т.е. всегда возвра-

щает false;
GL_AL AYS W

тест проходит всегда;

GL_LESS, GL_LEQUAL, GL_EQUAL GL_GEQUAL, GL_GREATE, GL_NOTEQUAL

проходит в случае, если

ref

тест

соответственно меньше значе-

ния в буфере маски, меньше либо равен, равен, больше, больше либо равен, или не равен. Аргумент mask задает маску для значений. Т.е. в итоге для этого теста получаем следующую формулу: ((ref AND mask) op (svalue AND mask)). Команда

glStencilOp

предназначена для определения действий

над пикселем буфера маски в случае положительного или отрицательного результата теста.


96

Глава 7. Операции с пикселями
Аргумент

sfail

задает действие в случае отрицательного ре-

зультата теста, и может принимать следующие значения:
GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR GL_DECR, GL_INVERT

соответственно сохраняет зна-

чение в буфере маски, обнуляет его, заменяет на заданное значение ( вертирует. Аргументы dpfail определяют действия в случае отрицательного результата теста на глубину в z-буфере, а dppass задает действие в случае положительного результата этого теста. Аргументы принимают те же значения, что и аргумент sfail. По умолчанию все три параметра установлены на GL_KEEP. ду Для включения маскирования необходимо выполнить команБуфер маски используется при создании таких спецэффектов, как падающие тени, отражения, плавные переходы из одной картинки в другую и пр. Пример использования буфера маски при построении теней и отражений приведен в разделах 8.2 и 8.3.

ref

), увеличивает, уменьшает или побитово ин-

glEnable(GL_STENCIL_TEST);

7.4. Управление растеризацией
Способ выполнения растеризации примитивов можно частично регулировать командой значений:
GL_FOG_HINT

glHint ( target , mode)

, где target вид

контролируемых действий, принимающий одно из следующих

точность вычислений при наложении ту-

мана. Вычисления могут выполняться по пикселям (наибольшая точность) или только в вершинах. Если реализация Op enGL не поддерживает попиксельного вычисления, то выполняется только вычисление по вершинам;


7.4. Управление растеризацией
GL_LINE_SMOOTH_HINT

97

управление качеством пря-

мых. При значении mo de, равным GL_NICEST, уменьшается ступенчатость прямых за счет большего числа пикселей в прямых;
GL_PERSPECTIVE_CORRECTION_HINT

точность

интерполяции координат при вычислении цветов и наложении текстуры. Если реализация Op enGL не поддерживает режим GL_NICEST, то осуществляется линейная интерполяция координат;
GL_POINT_SMOOTH_HINT

управление качеством то-

чек. При значении параметра mo de, равном GL_NICEST, точки рисуются как окружности;
GL_POLYGON_SMOOTH_HINT

управление

каче-

ством вывода сторон многоугольника.

Параметр mo de интерпретируется следующим образом:
GL_F ASTEST GL_NICEST

используется наиболее быстрый алгоритм;

используется алгоритм, обеспечивающий луч-

шее качество;
GL_DONT_CARE

выбор алгоритма зависит от реализа-

ции.

Важно заметить, что командой

glHint ()

программист может

только определить свои пожелания относительно того или иного аспекта растеризации примитивов. Конкретная реализация Op enGL вправе игнорировать данные установки. Обратите внимание, что раторными скобками

glHint () нельзя glBegin()/glEnd().

вызывать между опе-


98

Глава 7. Операции с пикселями

7.5. Контрольные вопросы
1) Какие буферы изображений используются в Op enGL и для чего? 2) Для чего используется команда

glBlendFunc?

3) Почему для корректного вывода прозрачных объектов требуется соблюдение условий упорядоченного вывода примитивов с прозрачностью? 4) Для чего используется буфер-накопитель? Приведите пример работы с ним. 5) Как в Op enGL можно наложить маску на результирующее изображение? 6) Объясните, для чего применятся команда 7) Каков эффект выполнения команды

glHint ()

.

glHint(GL_FOG_HINT, GL_DONT_CARE)?


Часть I I

Приемы работы с Op enGL

99



Глава 8.

Графические алгоритмы на основе Op enGL
В этой главе мы рассмотрим как с помощью Op enGL создавать некоторые интересные визуальные эффекты, непосредственная поддержка которых отсутствует в стандарте библиотеки.

8.1. Устранение ступенчатости
Начнем с задачи устранения ступенчатости (antialiasing). Эффект ступенчатости (aliasing) возникает в результате погрешностей растеризации примитивов в буфере кадра из-за конечного (и как правило, небольшого) разрешения буфера. Есть несколько подходов к решению данной проблемы. Например, можно применять фильтрацию полученного изображения. Также этот эффект можно устранять на этапе растеризации, сглаживая образ каждого примитива. Здесь мы рассмотрим прием, позволяющий устранять подобные артефакты для всей сцены целиком. Для каждого кадра необходимо нарисовать сцену несколько 101


102

Глава 8. Графические алгоритмы на основе OPENGL

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

1/n

, где

n

число проходов для каждого

кадра. Чем больше таких проходов тем ниже производительность, но лучше результат.

{

/ / о б ы ч н о s a m p l e s _ c o u n t лежит в п р е д е л а х от 5 д о 1 0

f o r ( i = 0 ; i
S h i f t C a m e r a ( i ) ; // с д в и г а е м камеру RenderScene ( ) ; i f ( i ==0)

else
}

g l A c c u m (GL_LOAD, 1 / ( f l o a t ) s a m p l e s _ c o u n t ) ;
/ / д о б а в л я е м к уже существующему

/ / н а п е р в о й итерации загружаем и з о б р а ж е н и е

g l A c c u m (GL_ACCUM, 1 / ( f l o a t ) s a m p l e s _ c o u n t ) ;

g l A c c u m (GL_RETURN, 1 . 0 ) ;

/ / Пишем то , что п о л у ч и л о с ь , н а з а д в и с х о д н ы й б у ф е р

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


8.2. Построение теней

103

8.2. Построение теней
В Op enGL нет встроенной поддержки построения теней на уровне базовых команд. В значительной степени это объясняется тем, что существует множество алгоритмов их построения, которые могут быть реализованы через функции Op enGL. Присутствие теней сильно влияет на реалистичность трехмерного изображения, поэтому рассмотрим один из подходов к их построению. Большинство алгоритмов, предназначенных для построения теней, используют модифицированные принципы перспективной проекции. Здесь рассматривается один из самых простых методов. С его помощью можно получать тени, отбрасываемые трехмерным объектом на плоскость. Общий подход таков: для всех точек объекта находится их проекция параллельно вектору, соединяющему данную точку и точку, в которой находится источник света, на некую заданную плоскость. Тем самым получаем новый объект, целиком лежащий в заданной плоскости. Этот объект и является тенью исходного. Рассмотрим математические основы данного метода. Пусть:
P

точка в трехмерном пространстве, которая отбрасывает тень.

L

положение источника света, который освещает данную точку.

S = a(L - P ) - P точка, P , где a параметр.

в которую отбрасывает тень точка

Предположим, что тень падает на плоскость случае

z=0

. В этом

a = zp /(zl - zp ).

Следовательно,


104

Глава 8. Графические алгоритмы на основе OPENGL
xs = (xp zl - zl zp )/(zl - zp ) ys = (yp zl - yl zp )/(zl - zp ) zs = 0
Введем однородные координаты:

xs ys zs ws
Отсюда координаты

= xs /ws = ys /ws = 0 = z l - zp

S

могут быть получены с использовани-

ем умножения матриц следующим образом:

xs y

s

0 ws = xs y

s

z

s

zl 0 0 zl 1 -xl -y 0 0



l

00 0 0 0 1 0 zl

Для того, чтобы алгоритм мог рассчитывать тень, падающую на произвольную плоскость, рассмотрим произвольную точку на линии между

S

и

aP + bL,
нормали:

где

P , представленную в однородных a и b скалярные параметры.

координатах:

Следующая матрица задает плоскость через координаты ее

xn yn G= zn d
данную точку рами



Точка, в которой луч, проведенный от источника света через

P

, пересекает плоскость

G

, определяется парамет-

a

и

b

, удовлетворяющими следующему уравнению:


8.2. Построение теней
(aP + bL)G = 0
Отсюда получаем: влетворяют

105

a(P G) + b(LG) = 0

. Этому уравнению удо-

a = (LG), b = -(P G)
Следовательно, координаты искомой точки

S = (LG)P -

(P G)L.

Пользуясь ассоциативностью матричного произведения,

получим

S = P [(LG)I - GL]
где

(8.1)

I

единичная матрица.

Матрица

(LG)I - GL

используется для получения теней на

произвольной плоскости. Рассмотрим некоторые аспекты практической реализации данного метода с помощью Op enGL. Предположим, что матрица нами из формулы

oorShadow

была ранее получена

(LG)I - GL.

Следующий код с ее помощью

строит тени для заданной плоскости:

/ * В и з у а л и з и р у е м с ц е н у в о б ы ч н о м режиме * /

RenderGeometry ( ) ;

/ * Д е л а е м тени п о л у п р о з р а ч н ы м и с и с п о л ь з о в а н и е м смешивания ц в е т о в ( b l e n d i n g ) * /

g g g g g

l E n a b l e (GL_BLEND ) ; l B l e n d F u n c (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ; l D i s a b l e ( GL_LIGHTING ) ; lColor4f (0.0 , 0.0 , 0.0 , 0.5); lPushMatrix ( ) ; glMultMatrixf ( ( GLfloat *) floorShadow ) ; /* Визуализируем с ц е н у в проекции */
/ * П р о е ц и р у е м тень * /


106

Глава 8. Графические алгоритмы на основе OPENGL

RenderGeometry ( ) ; glPopMatrix ( ) ; g l E n a b l e ( GL_LIGHTING ) ; g l D i s a b l e (GL_BLEND ) ;
Матрица o orShadow может быть получена из уравнения 8.1 с помощью следующей функции:

void s h a d o w m a t r i x ( G L f l o a t m a t r i x [ 4 ] [ 4 ] ,
{ GLfloat plane [ 4 ] , GLfloat l i g h t p o s [ 4 ] )

/ * параметры : p l a n e - коэффициенты у р а в н е н и я п л о с к о с т и l i g h t p o s - координаты источника света в о з в р а щ а е т : m a t r i x - р е з у л ь т и р у ю щ а я мат ри ца */

GLfloat dot ; dot = p p p p m m m m m m m m m m m m a a a a a a a a a a a a t t t t t t t t t t t t r r r r r r r r r r r r i i i i i i i i i i i i x x x x x x x x x x x x [ [ [ [ [ [ [ [ [ [ [ [ l l l l a a a a ] ] ] ] ] ] ] ] ] ] ] ] n n n n [ [ [ [ [ [ [ [ [ [ [ [ e e e e 0 0 0 0 1 1 1 1 2 2 2 2 [ [ [ [ ] ] ] ] ] ] ] ] ] ] ] ] 0 1 2 3 ] ] ] ]
* * * *

l l l l o . . . . o . . . . o . t f f f f t f f f f t f

i i i i

g g g g

h h h h

t t t t l l l l l l l l l l l l

p p p p i i i i i i i i i i i i

o o o o

s s s s

[ [ [ [ t t t t t t t t t t t t

0 1 2 3 p p p p p p p p p p p p

] ] ] ] o o o o o o o o o o o o

; s s s s s s s s s s s s

+ + + [ [ [ [ [ [ [ [ [ [ [ [ 0 0 0 0 1 1 1 1 2 2 2 2 ] ] ] ] ] ] ] ] ] ] ] ]
* * * * * * * * * * * *

0 1 2 3 0 1 2 3 0 1 2 3

= = = = = = = = = = = =

d 0 0 0 0 d 0 0 0 0 d 0

- - - - - - - - - - - -

g g g g g g g g g g g g

h h h h h h h h h h h h

p p p p p p p p p p p p

l l l l l l l l l l l l

a a a a a a a a a a a a

n n n n n n n n n n n n

e e e e e e e e e e e e

[ [ [ [ [ [ [ [ [ [ [ [

0 1 2 3 0 1 2 3 0 1 2 3

] ] ] ] ] ] ] ] ] ] ] ]

; ; ; ; ; ; ; ; ; ; ; ;


8.2. Построение теней
m m m m a a a a t t t t r r r r i i i i x x x x [ [ [ [ 0 1 2 3 ] ] ] ] [ [ [ [ 3 3 3 3 ] ] ] ] = = = = 0 0 0 d . . . o f f f t
- - - -

107

}

l l l l

i i i i

g g g g

h h h h

t t t t

p p p p

o o o o

s s s s

[ [ [ [

3 3 3 3

] ] ] ]

* * * *

p p p p

l l l l

a a a a

n n n n

e e e e

[ [ [ [

0 1 2 3

] ] ] ]

; ; ; ;

Заметим, что тени, построенные таким образом, имеют ряд недостатков:



Описанный алгоритм предполагает, что плоскости бесконечны, и не отрезает тени по границе. Например, если некоторый объект отбрасывает тень на стол, она не будет отсекаться по границе, и, тем более, ?заворачиваться? на боковую поверхность стола. В некоторых местах теней может наблюдаться эффект ?двойного смешивания? (reblending), т.е. темные пятна в тех участках, где спроецированные треугольники перекрывают друг друга. С увеличением числа поверхностей сложность алгоритма резко увеличивается, т.к. для каждой поверхности нужно заново строить всю сцену, даже если проблема отсечения теней по границе будет решена. Тени обычно имеют размытые границы, а в приведенном алгоритме они всегда имеют резкие края. Частично избежать этого позволяет расчет теней из нескольких источников света, расположенных рядом и последующее смешивание результатов.

Имеется решение первой и второй проблемы. Для этого используется буфер маски (см. п. 7.2). Итак, задача отсечь вывод геометрии (тени) по границе некоторой произвольной области и избежать ?двойного смеши-


108

Глава 8. Графические алгоритмы на основе OPENGL

вания?. Общий алгоритм решения с использованием буфера маски таков: 1) очищаем буфер маски значением 0; 2) отображаем заданную область отсечения, устанавливая

значения в буфере маски в 1; 3) рисуем тени в тех областях, где в буфере маски установлены значения; если тест проходит, устанавливаем в эти области значение 2. Теперь рассмотрим эти этапы более подробно. 1.

/ * очищаем б у ф е р м а с к и * /

g l C l e a r S t e n c i l ( 0 x0 ) g l C l e a r ( GL_STENCIL_BUFFER_BIT ) ;

/ * в к л ю ч а е м тест * /
2.

g l E n a b l e ( GL_STENCIL_TEST ) ;

/* у с л о в и е в с е г д а выполнено и з н а ч е н и е в б у ф е р е будет р а в н о 1 */

g l S t e n c i l F u n c (GL_ALWAYS, 0 x 1 , 0 x f f f f f f f f ) ;

/ * в любом с л у ч а е з а м е н я е м з н а ч е н и е в б у ф е р е м а с к и * /

g l S t e n c i l O p (GL_REPLACE, GL_REPLACE, GL_REPLACE ) ;

/ * в ы в о д и м геометрию , п о к о т о р о й затем б у д е т о т с е ч е н а т е н ь * /

RenderPlane ( ) ;
3.

/ * у с л о в и е в ы п о л н е н о и тест д а е т истину т о л ь к о е с л и з н а ч е н и е в б у ф е р е маски р а в н о 1 * /


8.3. Зеркальные отражения
g l S t e n c i l F u n c (GL_EQUAL, 0 x 1 , 0 x f f f f f f f f ) ;

109

/ * з н а ч е н и е в б у ф е р е р а в н о 2 , е с л и тень уже в ы в е д е н а * /

g l S t e n c i l O p (GL_KEEP, GL_KEEP, GL_INCR ) ;

RenderShadow ( ) ;

/ * в ы в о д и м те ни * /
Строго говоря, даже при применении маскирования остают-

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

8.3. Зеркальные отражения
В этом разделе мы рассмотрим алгоритм построения отражений от плоских объектов. Такие отражения придают большую достоверность построенному изображению и их относительно легко реализовать. Алгоритм использует интуитивное представление полной сцены с зеркалом как составленной из двух: ?настоящей? и ?виртуальной? находящейся за зеркалом. Следовательно, процесс рисования отражений состоит из двух частей: 1) визуализации обычной сцены и 2) построения и визуализации виртуальной. Для каждого объекта ?настоящей? сцены строится его отраженный двойник, который наблюдатель и увидит в зеркале. Для иллюстрации рассмотрим комнату с зеркалом на стене. Комната и объекты, находящиеся в ней, выглядят в зеркале так, как если бы зеркало было окном, а за ним была бы еще одна такая же комната с тем же объектами, но симметрично отраженными относительно плоскости, проведенной через поверхность


110

Глава 8. Графические алгоритмы на основе OPENGL

Рис. 8.1. Зеркальное отражение

зеркала. Упрощенный вариант алгоритма создания плоского отражения состоит из следующих шагов: 1) Рисуем сцену как обычно, но без объектов-зеркал. 2) Используя буфер маски, ограничиваем дальнейший вывод проекцией зеркала на экран. 3) Визуализируем сцену, отраженную относительно плоскости зеркала. При этом буфер маски позволит ограничить вывод формой проекции объекта-зеркала. Эта последовательность действий позволит получить убедительный эффект отражения. Рассмотрим этапы более подробно. Сначала необходимо нарисовать сцену как обычно. Не будем останавливаться на этом этапе подробно. Заметим только, что, очищая буферы Op enGL непосредственно перед рисованием, нужно не забыть очистить буфер маски:


8.3. Зеркальные отражения
g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ;

111

Во время визуализации сцены лучше не рисовать объекты, которые затем станут зеркальными. На втором этапе необходимо ограничить дальнейший вывод проекцией зеркального объекта на экран. Для этого настраиваем буфер маски и рисуем зеркало

/* у с л о в и е в с е г д а выполнено и з н а ч е н и е в бу ф ер е будет р а в н о 1 */

g l E n a b l e ( GL_STENCIL_TEST ) ;

g l S t e n c i l F u n c (GL_ALWAYS, 1 , 0 ) ; g l S t e n c i l O p (GL_KEEP, GL_KEEP, GL_REPLACE ) ;

RenderMirrorObject ( ) ;



В результате мы получили: в буфере кадра корректно нарисованная сцена, за исключением области зеркала; в области зеркала (там, где мы хотим видеть отражение) значение буфера маски равно 1.

На третьем этапе нужно нарисовать сцену, отраженную относительно плоскости зеркального объекта. Сначала настраиваем матрицу отражения. Матрица отражения должна зеркально отражать всю геометрию относительно плоскости, в которой лежит объект-зеркало. Ее можно получить, например, с помощью такой функции (попробуйте получить эту матрицу самостоятельно в качестве упражнения):

void r e f l e c t i o n m a t r i x ( G L f l o a t r e f l e c t i o n _ m a t r i x [ 4 ] [ 4 ] ,
{ GLfloat plane_point [ 3 ] , G l f l o a t plane_normal [ 3 ] )

GLfloat * p ;


112

Глава 8. Графические алгоритмы на основе OPENGL

GLfloat * v ; f l o a t pv ; GLfloat * p = ( G l f l o a t *) plane_point ; G l f l o a t * v = ( G l f l o a t * ) plane_normal ; f l o a t pv = p [ 0 ] * v [ 0 ] + p [ 1 ] * v [ 1 ] + p [ 2 ] * v [ 2 ] ; r r r r r r r r r r r r r r r r e e e e e e e e e e e e e e e e f f f f f f f f f f f f f f f f l l l l l l l l l l l l l l l l e e e e e e e e e e e e e e e e c c c c c c c c c c c c c c c c t t t t t t t t t t t t t t t t i i i i i i i i i i i i i i i i o o o o o o o o o o o o o o o o n n n n n n n n n n n n n n n n _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ m m m m m m m m m m m m m m m m a a a a a a a a a a a a a a a a t t t t t t t t t t t t t t t t r r r r r r r r r r r r r r r r i i i i i i i i i i i i i i i i x x x x x x x x x x x x x x x x [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] = = = = = = = = = = = = = = = = 1-2 -2* -2* 2*p
-2* 1- 2 -2* 2*p -2* -2* 1-2 2*p
* v[0] * v [0]; v[0] * v [1]; v[0] * v [2]; v * v[0];

v[0] * * v[1] * v[1] * v * v[1]

v[1]; v[1]; v[2]; ;

v[0] * v [2]; v[1] * v [2]; * v[2] * v [2]; v * v[2];

}

0 0 0 1

; ; ; ;

Настраиваем буфер маски на рисование только в областях, где значение буфера равно 1:

/ * у с л о в и е в ы п о л н е н о и тест д а е т истину только е с л и з н а ч е н и е в б у ф е р е маски р а в н о 1 * /

g l S t e n c i l F u n c (GL_EQUAL, 0 x 1 , 0 x f f f f f f f f ) ;

/ * н и ч е г о н е меняем в б у ф е р е * /

g l S t e n c i l O p (GL_KEEP, GL_KEEP, GL_KEEP ) ;

и рисуем сцену еще раз (без зеркальных объектов)


8.4. Контрольные вопросы
glPushMatrix glMultMatrix RenderScene ( glPopMatrix ( ( f ) ) ); ( ( float *) r e f l e c t i o n _ m a t r i x ) ; ; ;

113

Наконец, отключаем маскирование:

g l D i s a b l e ( GL_STENCIL_TEST ) ;
После этого можно опционально еще раз вывести зеркальный объект, например, с альфа-смешением для создания эффекта замутнения зеркала и т.д. Обратите внимание, что описанный метод корректно работает, только если за зеркальным объектом нет других объектов сцены. Поэтому существует несколько модификаций этого алгоритма, отличающихся последовательностью действий и имеющих разные ограничения на геометрию.

8.4. Контрольные вопросы

В результате чего возникает эффект ступенчатости изображения? Опишите алгоритм устранения ступенчатости. Почему в Op enGL нет встроенной поддержки построения теней? Кратко опишите предложенный метод визуализации зеркальных объектов. Почему он не работает, если за зеркалом находятся другие объекты сцены? Что будет отражаться в этом случае? Подумайте, как обойти это ограничение?



Глава 9.

Оптимизация программ

9.1. Организация приложения
На первый взгляд может показаться, что производительность графических приложений, основанных на Op enGL, определяется в первую очередь производительностью реализации самой библиотеки. Это верно, однако организация всего приложения также очень важна.

9.1.1. Высокоуровневая оптимизация
Обычно от программы под Op enGL требуется визуализация высокого качества на интерактивных скоростях. Но как правило, и то и другое сразу получить не удается. Следовательно, необходим поиск компромисса между качеством и производительностью. Существует множество различных подходов, но их подробное описание выходит за пределы этого пособия. Приведем лишь несколько примеров.



Можно отображать геометрию сцены с низким качеством во время анимации, а в моменты остановок показывать ее с 115


116

Глава 9. Оптимизация программ
наилучшим качеством. Во время интерактивного вращения (например, при нажатой клавише мыши) визуализировать модель с уменьшенным количеством примитивов. При рисовании статичного изображения отображать модель полностью. Аналогично, объекты, которые располагаются далеко от наблюдателя, могут быть представлены моделями пониженной сложности. Это значительно снизит нагрузку на все ступени конвейера Op enGL. Объекты, которые находятся полностью вне поля видимости, могут быть эффективно отсечены без передачи на конвейер Op enGL с помощью проверки попадания ограничивающих их простых объемов (сфер или кубов) в пирамиду зрения.



9.1.2. Низкоуровневая оптимизация
Объекты, отображаемые с помощью Op enGL, хранятся в некоторых структурах данных. Одни типы таких структур более эффективны в использовании, чем другие, что определяет скорость визуализации. Желательно, чтобы использовались структуры данных, которые могут быть быстро и эффективно переданы на конвейер Op enGL. Например, если мы хотим отобразить массив треугольников, то использование указателя на этот массив значительно более эффективно, чем передача его Op enGL поэлементно. Пример. Предположим, что мы пишем приложение, которое реализует рисование карты местности. Один из компонентов базы данных список городов с их шириной, долготой и названием. Соответствующая структура данных может быть такой:

{

struct c i t y float latitute , longitude ; c h a r * name ;
/ * положение г о р о д а * / /* н а з в а н и е */


9.1. Организация приложения
};

117

int l a r g e _ f l a g ;

/ * 0 = маленький , 1 = большой * /

Список городов может храниться как массив таких структур. Допустим, мы пишем функцию, которая рисует города на карте в виде точек разного размера с подписями:

{

void d r a w _ c i t i e s ( i n t n , s t r u c t c i t y c i t y l i s t [ ] ) int i ; f o r ( i = 0 ; i < n ; i ++)
{

if ( c i t y l i s t [ i ] . large_flag )
glPointSize ( 4.0 ) ; glPointSize ( 2.0 ) ;

else

}

}

DrawText ( c i t y l i s t [ i ] . l o n g i t u d e , c i t y l i s t [ i ] . latitude , c i t y l i s t [ i ] . name ) ;

/* рисуем н а з в а н и е г о р о д а */

g l B e g i n ( GL_POINTS ) ; glVertex2f ( c i t y l i s t [ i ] . longitude , ci ty li st [ i ] . latitude ); glEnd ( ) ;


{

Эта реализация неудачна по следующим причинам:

glPointSize
между

вызывается для каждой итерации цикла; и

glBegin

glEnd

рисуется только одна точка;

вершины определяются в неоптимальном формате.

Ниже приведено более рациональное решение:

void d r a w _ c i t i e s ( i n t n , s t r u c t c i t y c i t y l i s t [ ] )


118

Глава 9. Оптимизация программ
glPointSize ( 2.0 ) ; g l B e g i n ( GL_POINTS ) ; f o r ( i = 0 ; i < n ; i ++) { i f ( c i t y l i s t [ i ] . l a r g e _ f l a g ==0) { glVertex2f ( c i t y l i s t [ i ] . longitude , ci ty li st [ i ] . latitude ); } } glEnd ( ) ; glPointSize ( 4.0 ) ; g l B e g i n ( GL_POINTS ) ; f o r ( i = 0 ; i < n ; i ++) { i f ( c i t y l i s t [ i ] . l a r g e _ f l a g ==1) { glVertex2f ( c i t y l i s t [ i ] . longitude , ci ty li st [ i ] . latitude ); } } glEnd ( ) ;
/ * с н а ч а л а р и с у е м м а л е н ь к и е точки * /

int i ;

/ * б о л ь ш и е т о ч к и р и с у е м в о вторую о ч е р е д ь * /

}

f o r ( i =0; i < { DrawText ( c i t y city city }

/ * затем р и с у е м н а з в а н и я г о р о д о в * /

n ; i ++)

l i s t [ i ] . longitude , l i s t [ i ] . latitude , l i s t [ i ] . name ) ;

В такой реализации мы вызываем личиваем число вершин между

glBegin

glPointSize и glEnd.

дважды и уве-

Однако остаются еще пути для оптимизации. Если мы поме-


9.1. Организация приложения
тивность рисования точек. Например:

119

няем наши структуры данных, то можем еще повысить эффек-

{

struct c i t y _ l i s t int num_c float * pos c h a r * * nam float s i z e
ities ; ition e; ; ; / * координаты г о р о д а * /
/* число г о р о д о в в с п и с к е */ /* ук аза те ль на н а з в а н и я г о р о д о в */ / * р а з м е р точки , о б о з н а ч а ю щ е й г о р о д * /

};

Теперь города разных размеров хранятся в разных списках. Положения точек хранятся отдельно в динамическом массиве. После реорганизации мы исключаем необходимость в условном операторе внутри

glBegin/glEnd

и получаем возможность исполь-

зовать массивы вершин для оптимизации. В результате наша функция выглядит следующим образом:

void d r a w _ c i t i e s ( s t r u c t c i t y _ l i s t
{

*list )

int i ;

/ * р и с у е м точки * / g l P o i n t S i z e ( l i s t -> s i z e ) ;

{

/* рисуем н а з в а н и е г о р о д а */ f o r ( i = 0 ; i < l i s t ->n u m _ c i t i e s ; i ++)

g l V e r t e x P o i n t e r ( 2 , GL_FLOAT, l i s t ->n u m _ c i l i s t -> p o s i t i o g l D r a w A r r a y s ( GL_POINTS , 0 , l i

0, ties , n ); s t ->n u m _ c i t i e s ) ;

}

}

DrawText ( c i t y l i s t [ i ] . l o n g i t u d e , ci ty li st [ i ] . latitude c i t y l i s t [ i ] . name ) ;


120

Глава 9. Оптимизация программ

9.2. Оптимизация вызовов OpenGL
9.2.1. Передача данных в Op enGL
В данном разделе рассмотрим способы минимизации времени на передачу данных о примитивах в Op enGL.

Используйте связанные примитивы

Связанные примитивы, такие как GL_LINES, GL_LINE_LOOP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN и GL_QUAD_STRIP требуют для определения меньше вершин, чем отдельные линия или многоугольник. Это уменьшает количество данных, передаваемых Op enGL.

Используйте массивы вершин

glVertex/glColor/glNormal

На большинстве архитектур замена множественных вызовов на механизм массивов вершин может

быть очень выигрышной.

Используйте индексированные примитивы

В некоторых случаях даже при использовании связанных примитивов

GL_TRIANGLE_STRIP (GL_QUAD_STRIP

) верши-

ны дублируются. Чтобы не передавать в Op enGL дубли, увеличивая нагрузку на шину, используйте команду

glDrawElements().

Задавайте необходимые массивы одной командой

glNormalPointer

Вместо использования команд

glVertexPointer, glColorPointer,

лучше пользоваться одной командой

void g l I n t e r l e a v e d A r r a y s ( G l i n t f o r m a t , void

Glsizei stride , * ptr ) ;


9.2. Оптимизация вызовов OPENGL
Так, если имеется структура

121

{

t y p e d e f s t r u c t tag_VERTEX_DATA float color [ 4 ] ; f l o a t normal [ 3 ] ; float vertex [ 3 ] ;

}VERTEX_DATA ; VERTEX_DATA * p D a t a ;
то параметры можно передать с помощью следующей команды

g l I n t e r l e a v e d A r r a y s ( GL_C4F_N3F_V3F, 0 , p D a t a ) ;
что означает, что первые четыре три

oat

oat

к нормали, и последние три

oat

относятся к цвету, затем задают координаты

вершины. Более подробное описание команды смотрите в спецификации Op enGL.

Храните данные о вершинах в памяти последовательно

Последовательное расположение данных в памяти улучшает скорость обмена между основной памятью и графической подсистемой. Используйте векторные версии .

glTexCoord

glVertex, glColor, glNormal glVertex3fv(v)

и

Функции

glVertex, glColor

и т.д., которые в качестве аргу), могут

ментов принимают указатели (например,

работать значительно быстрее, чем их соответствующие версии

glVertex3f (x , y , z)

.

Уменьшайте сложность примитивов

Во многих случаях будьте внимательны, чтобы не разбивать большие плоскости на части сильнее, чем необходимо. Поэкспериментируйте, например, с примитивами GLU для определения наилучшего соотношения качества и производительности.


122

Глава 9. Оптимизация программ

Текстурированные объекты, например, могут быть качественно отображены с небольшой сложностью геометрии.

Используйте дисплейные списки

Используйте дисплейные списки для наиболее часто выводимых объектов. Дисплейные списки могут храниться в памяти графической подсистемы и, следовательно, исключать частые перемещения данных из основной памяти.

Не указывайте ненужные атрибуты вершин

Если освещение выключено, не вызывайте используются текстуры, не вызывайте

glNormal. glTexCoord, и т.д.

Если не

Минимизируйте количество лишнего кода между операторными скобками

glBegin/glEnd

Для максимальной производительности на high-end системах важно, чтобы информация о вершинах была передана графической подсистеме максимально быстро. Избегайте лишнего кода между

glBegin/glEnd.

Пример неудачного решения:

{

f o r ( i = 0 ; i < n ; i ++)
{

g l B e g i n ( GL_TRIANGLE_STRIP ) ;

if ( lighting )

} glEnd ( ) ;

g l N o r m a l 3 f v ( norm [ i ] ) ; } glVertex3fv ( vert [ i ] ) ;


9.2. Оптимизация вызовов OPENGL
lighting

123

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

частичного дублирования кода:

{

if ( lighting ) f o r ( i = 0 ; i < n ; i ++)
g l B e g i n ( GL_TRIANGLE_STRIP ) ; g l N o r m a l 3 f v ( norm [ i ] ) ; glVertex3fv ( vert [ i ] ) ;

{

} {

} glEnd ( ) ;

else f o r ( i = 0 ; i < n ; i ++)
g l B e g i n ( GL_TRIANGLE_STRIP ) ;

{

}

glVertex3fv ( vert [ i ] ) ; } glEnd ( ) ;

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

glVertex,

к оконным координатам, отсе-

Освещение



Избегайте использования точечных источников света. Избегайте использования двухстороннего освещения (twosided lighting).


124

Глава 9. Оптимизация программ



Избегайте использования локальной модели освещения. Избегайте частой смены параметра

GL_SHININESS

.

Рассмотрите возможность заранее просчитать освещение. Можно получить эффект освещения, задавая цвета вершин вместо нормалей.

Отключайте

нормализацию

векторов

нормалей,

когда

это не является необходимым

Команда

glEnable/Disable(GL_NORMALIZE) glScale

управляет норма-

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

Используйте связанные примитивы

Связанные примитивы, такие как GL_LINES, GL_LINE_LOOP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, и GL_QUAD_STRIP уменьшают нагрузку на конвейер Op enGL, а также уменьшают количество данных, передаваемых графической подсистеме.

9.2.3. Растеризация
Растеризация часто является узким местом программных реализаций Op enGL.

Отключайте тест на глубину, когда в этом нет необходимости

Фоновые объекты, например, могут быть нарисованы без теста на глубину, если они визуализируется первыми.


9.2. Оптимизация вызовов OPENGL
Используйте отсечение обратных граней полигонов

125

Замкнутые объекты могут быть нарисованы с установленным режимом отсечения обратных граней не растеризуя их.

glEnable(GL_CULL_FACE)

Иногда это позволяет отбросить до половины многоугольников,

Избегайте лишних операций с пикселями

Маскирование, альфа-смешивание и другие попиксельные операции могут занимать существенное время на этапе растеризации. Отключайте все операции, которые вы не используете.

Уменьшайте размер окна или разрешение экрана

Простой способ уменьшить время растеризации уменьшить число пикселей, которые будут нарисованы. Если меньшие размеры окна или меньшее разрешение экрана приемлемы, то это хороший путь для увеличения скорости растеризации.

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

Используйте эффективные форматы хранения изображений

Формат

GL_UNSIGNED_BYTE

обычно наиболее всего подхо-

дит для передачи текстуры в Op enGL.

Объединяйте текстуры в текстурные объекты или дисплейные списки.

Это особенно важно, если вы используете несколько текстур, и позволяет графической подсистеме эффективно управлять


126

Глава 9. Оптимизация программ

размещением текстур в видеопамяти.

Не используйте текстуры большого размера

Небольшие текстуры быстрее обрабатываются и занимают меньше памяти, что позволяет хранить сразу несколько текстур в памяти графической подсистемы.

Комбинируйте небольшие текстуры в одну

Если вы используете несколько маленьких текстур, то можно объединить их в одну большего размера и изменить текстурные координаты для работы с нужной подтекстурой. Это позволяет уменьшить число переключений текстур.

Анимированные текстуры

Если вы хотите использовать анимированные текстуры, не используйте команду или

glTexImage2D

чтобы обновлять образ тек-

стуры. Вместо этого рекомендуется вызывать

glTexCopyTexSubImage2D.

glTexSubImage2D

9.2.5. Очистка буферов
Очистка буферов цвета, глубины, маски и буфера-накопителя может требовать значительного времени. В этом разделе описаны некоторые приемы, которые могут помочь оптимизировать эту операцию.

Используйте команду glClear с осторожностью

Очищайте все нужные буферы с помощью одной команды glClear. Неверно:


9.2. Оптимизация вызовов OPENGL
g l C l e a r (GL_COLOR_BUFFER_BIT ) ; i f ( s t e n c i l i n g ) / * очистить б у ф е р м а с к и ? * / { g l C l e a r ( GL_STENCIL_BUFFER_BIT ) ; }
Верно:

127

{ } { }

if ( stenciling )

/ * очистить б у ф е р м а с к и ? * /

g l C l e a r (GL_COLOR_BUFFER_BIT | STENCIL_BUFFER_BIT ) ;

else
g l C l e a r (GL_COLOR_BUFFER_BIT ) ;

9.2.6. Разное
Проверяйте ошибки GL во время написания программ

Вызывайте команду

glGetError()

для проверки, не произошло

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

#i n c l u d e < a s s e r t . h> #d e f i n e CHECK_GL \

a s s e r t ( g l G e t E r r o r ( ) ! = GL_NO_ERROR ) ;

Использовать его можно так:

g l B e g i n (GL_TRIANGLES ) ; glVertex3f (1 ,1 ,1); glEnd ( ) ;


128

Глава 9. Оптимизация программ

CHECK_GL ;
Используйте

glColorMaterial

вместо

glMaterial

Если в сцене материалы объектов различаются лишь одним параметром, команда

glMaterial

glColorMaterial

может быть быстрее, чем

.

Минимизируйте число изменений состояния Op enGL

glBindTexture

Команды, изменяющие состояние Op enGL (

glEnable, glDisable

,

и другие), вызывают повторные внутренние про-

верки целостности, создание дополнительных структур данных и т.д., что может приводить к задержкам.

Избегайте использования команды glPolygonMo de

Если вам необходимо рисовать много незакрашенных мно-

GL_LINE_LOOP
рее.

гоугольников, используйте или

glBegin с GL_POINTS, GL_LINES, GL_LINE_STRIP вместо изменения режима

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

9.3. Контрольные вопросы
1) Перечислите известные вам методы высокоуровневой оптимизации Op enGL-приложений. 2) Почему предпочтительнее использование связанных примитивов?


9.3. Контрольные вопросы
3) Какая из двух команд выполняется Op enGL быстрее?

129

glVertex3f (1 ,1 ,1);
или

float vct [ 3 ] = {1 ,1 ,1};
glVertex3fv ( vct ) ;



Часть I I I

Создание приложений с Op enGL

131



Глава 10.

Op enGL-приложения с помощью GLUT

10.1. Структура GLUT-приложения
Далее будем рассматривать построение консольного приложения при помощи библиотеки GLUT. Эта библиотека обеспечивает единый интерфейс для работы с окнами вне зависимости от платформы, поэтому описываемая ниже структура приложения остается неизменной для операционных систем Windows, Linux и других. Функции GLUT могут быть классифицированы на несколько групп по своему назначению:



инициализация; начало обработки событий; управление окнами; управление меню; регистрация функций с обратным вызовом; 133


134

Глава 10. OPENGL-приложения с помощью GLUT



управление индексированной палитрой цветов; отображение шрифтов; отображение дополнительных геометрических фигур (тор, конус и др.).

Инициализация проводится с помощью функции:

g l u t I n i t ( i n t * a r g c p , char * * a r g v )
Переменная ную

argc

argcp

есть указатель на стандартную перемен-

, описываемую в функции

main()



argv

указатель на

параметры, передаваемые программе при запуске, который описывается там же. Эта функция проводит необходимые начальные действия для построения окна приложения, и только несколько функций GLUT могут быть вызваны до нее. К ним относятся:

glutInitWindowPosition ( int x , int y ) g l u t I n i t W i n d o w S i z e ( i n t width , i n t h e i g h t ) g l u t I n i t D i s p l a y M o d e ( u n s i g n e d i n t mode )
Первые две функции задают соответственно положение и размер окна, а последняя функция определяет различные режимы отображения информации, которые могут совместно задаваться с использованием операции побитового ?или? (? | ?):
GLUT_RGBA Режим RGBA. Используется по умолчанию, ес-

ли не указаны режимы GLUT_RGBA или
GLUT_RGB То же, что и

GLUT_INDEX

.

GLUT_RGBA

.

GLUT_INDEX Режим индексированных цветов (использова-

ние палитры). Отменяет

GLUT_RGBA

.

GLUT_SINGLE Окно с одиночным буфером. Используется

по умолчанию.
GLUT_DOUBLE Окно с двойным буфером.

Отменяет

GLUT_SINGLE.


10.1. Структура GLUT-приложения
GLUT_STENCIL Окно с буфером маски. GLUT_ACCUM Окно с буфером-накопителем. GLUT_DEPTH Окно с буфером глубины.

135

Это неполный список параметров для данной функции, однако для большинства случаев этого бывает достаточно. Работа с буфером маски и буфером накопления описана в главе 7. Функции библиотеки GLUT реализуют так называемый событийно-управляемый механизм. Это означает, что есть некоторый внутренний цикл, который запускается после соответствующей инициализации и обрабатывает одно за другим все события, объявленные во время инициализации. К событиям относятся: щелчок мыши, закрытие окна, изменение свойств окна, передвижение курсора, нажатие клавиши и ?пустое? (idle) событие, когда ничего не происходит. Для проведения периодической проверки совершения того или иного события надо зарегистрировать функцию, которая будет его обрабатывать. Для этого используются функции вида:

void g l u t D i s p l a y F u n c ( void ( * f u n c ) ( void ) ) void g l u t R e s h a p e F u n c ( void ( * f u n c ) ( i n t w i d t h int heigh void g l u t M o u s e F u n c ( void ( * f u n c ) ( i n t b u t t o n int state , int x , int y ) void g l u t I d l e F u n c ( void ( * f u n c ) ( void ) ) void g l u t M o t i o n F u n c ( void ( * f u n c ) ( i n t x , i n t void g l u t P a s s i v e M o t i o n F u n c ( void ( * f u n c ) ( i n t x , i n t
ции заданного типа. С помощью

, t )) , ) y)); y));

Параметром для них является имя соответствующей функ-

glutDisplayFunc()

задается функ-

ция рисования для окна приложения, которая вызывается при необходимости создания или восстановления изображения. Для


136

Глава 10. OPENGL-приложения с помощью GLUT

явного указания, что окно надо обновить, иногда удобно использовать функцию

void g l u t P o s t R e d i s p l a y ( void )
Через

glutReshapeFunc()

устанавливается функция обработки

изменения размеров окна пользователем, которой передаются новые размеры. мыши, а

glutMouseFunc() определяет функцию-обработчик glutIdleFunc() задает функцию, которая будет
Функция, определяемая

команд от вызывать-

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

glutMotionFunс(),

вызывается, когда

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

glutPassiveMotionFunc

регистрирует функцию, вызываемую,

если пользователь двигает указатель мыши и не нажато ни одной кпопки мыши. Контроль всех событий происходит внутри бесконечного цикла в функции

void

glutMainLoop

( void )

которая обычно вызывается в конце любой программы, использующей GLUT. Структура приложения, использующего анимацию, будет следующей:

#i n c l u d e { ... }; {

void M y I d l e ( void )
/ * К о д , к о т о р ы й меняет п е р е м е н н ы е , о п р е д е л я ю щ и е следующий к а д р * /

void MyDisplay ( void )
/ * Код OpenGL , который отображает к а д р * /

...


10.2. GLUT в среде MICROSOFT VISUAL C++ 6.0
/* После р и с о в а н и я переставляем

137

glutSwapBuffers ( ) ; };

буферы * /

{

void main ( i n t a r g c p , char
/ * И н и ц и а л и з а ц и я GLUT * /

** a r g v )

/ * Открытие о к н а * / / * Выбор режима :

g l u t I n i t (& a r g c p , a r g v ) ; glutInitWindowSize (640 , 480); glutInitWindowPosition (0 , 0 ) ;
д в о й н о й б у ф е р и RGBA ц в е т а * /

g l u t C r e a t e W i n d o w ( "My OpenGL A p p l i c a t i o n " ) ;

/ * Р е г и с т р а ц и я вызываемых функций * /

g l u t I n i t D i s p l a y M o d e (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH ) ;

glutMainLoop ( ) ; };

/ * З а п у с к м е х а н и з м а о б р а б о т к и событий * /

g l u t D i s p l a y F u n c ( MyDisplay ) ; g l u t I d l e F u n c ( MyIdle ) ;

В случае , если приложение должно строить статичное изображение, можно заменить вызов функции

GLUT_DOUBLE
.

на

GLUT_SINGLE,

так как одного буфера в этом случае будет достаточно, и убрать

glutIdleFunc()

10.2. GLUT в среде Microsoft Visual C++ 6.0
Перед началом работы необходимо скопировать файлы glut.h, glut32.lib glut32.dll в каталоги MSVC\Include\Gl, MSVC\Lib, Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, op engl32.lib, glu32.lib, op engl32.dll, glu32.dll, которые обычно входят в состав Visual C++ и Windows. При использовании команд из библиотеки


138

Глава 10. OPENGL-приложения с помощью GLUT

GLAUX к перечисленным файлам надо добавить подключаемые файлы библиотеки glaux.h и glaux.lib. Для создания приложения надо выполнить следующие действия:



Создание проекта: для этого надо выбрать File Pro jects OK.



Win32 Console Application, набрать имя проекта,


New

В появившемся окне выбрать ?An empty pro ject?, Finish, OK. Текст программы можно либо разместить в созданном текстовом файле (выбрав File брав Pro ject New Files Text File), либо добавить файл с расширением *.c или *.cpp в проект (выAdd To Pro ject Files).







Подключить к проекту библиотеки Op enGL. Для этого надо выбрать Pro ject Settings Link и в поле Ob ject\library mo dules набрать названия нужных библиотек: op engl32.lib, glu32.lib, glut32.lib и, если надо, glaux.lib. Для компиляции выбрать Build выполнения Build





Execute program.exe.



Build program.exe, для

Чтобы при запуске не появлялось текстовое окно, надо выбрать Pro ject Settings Link и в поле Pro ject Options вместо ?subsystem:console? набрать ?subsystem:windows?, и набрать там же строку ?/entry:mainCRTStartup?.





Когда программа готова, рекомендуется перекомпилировать ее в режиме ?Release? для оптимизации по быстродействию и объему. Для этого надо выбрать Build ходимые библиотеки. Set Active Conguration и отметить ?. . . -Win32 Release?, а затем заново подключить необ-




10.3. GLUT в среде MICROSOFT VISUAL C++ 2005

139

10.3. GLUT в среде Microsoft Visual C++ 2005
Перед началом работы необходимо скопировать файлы glut.h, glut32.lib и glut32.dll в каталоги MVS8\VC\PlatformSDK\Include, MVS8\VC\PlatformSDK\Lib, Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, op engl32.lib, glu32.lib, op engl32.dll, glu32.dll, которые обычно входят в состав Visual C++ и Windows. При использовании команд из библиотеки GLAUX к перечисленным файлам надо добавить подключаемые файлы библиотеки glaux.h и glaux.lib. Для создания приложения надо выполнить следующие действия:



Создание проекта: для этого надо выбрать File Pro jects Win32 проекта, OK.





Win32 Console Application, набрать имя


New

В появившемся окне во вкладке Application Settings выбрать ?Console application?, ?An empty pro ject?, Finish. Текст программы можно либо разместить в созданном текстовом файле (выбрав File в проект (выбрав Pro ject New Files Visual C++

C++File ), либо добавить файл с расширением *.c или *.cpp Add To Pro ject Files).









Подключить к проекту библиотеки Op enGL. Для этого надо выбрать Pro ject Linker

звания нужных библиотек: op engl32.lib, glu32.lib, glut32.lib и, если надо, glaux.lib. Для компиляции выбрать Build нения Debug Debugging.



Input и в поле Additional dep endencies набрать на-



Prop erties

Conguration Prop erties





Start Debugging или Debug



program.exe, для выполStart Without




140

Глава 10. OPENGL-приложения с помощью GLUT



Чтобы при запуске программы не появлялось консольное текстовое SubSystem окно, вместо надо Conguration Prop erties

?Console?

рейти в раздел Linker

написать ?wmainCRTStartup? (без кавычек). Когда программа готова, рекомендуется перекомпилировать ее в режиме ?Release? для оптимизации по быстродействию и объему. Для этого надо выбрать Build Conguration Manager и в поле ?Active solution conguration? выбрать ?Release?, а затем заново подключить необходимые библиотеки для этой конфигурации.





выбрать Linker

выбрать



Pro ject

System



Prop erties в

и

поле Пе-



?Windows?.

Advanced и в поле Entry Point



10.4. GLUT в среде Borland C++ Builder 6
Перед glut.h, этих началом работы необходимо в каталоги скопировать файлы в glut32.lib, glut32.dll CBuilder6\Include\Gl, Также gl.h, файлов glu.h, CBuilder6\Lib, каталогах op engl32.lib, Windows\System надо проверить op engl32.dll, соответственно. наличие glu32.dll, glu32.lib, которые обычно

входят в состав Borland C++ и Windows. При этом надо учитывать, что оригинальные (для Microsoft Visual C++) версии файла glut32.lib c Borland C++ Builder 6 работать не будут, и следует использовать только совместимую версию. Чтобы создать такую версию, надо использовать стандартную программу 'implib', которая находится в каталоге СBuilder6\Bin. Для этого в командной строке надо выполнить команду

implib glut32.lib
ла.

glut32.dll

которая создает нужный lib-файл из соответствующего dll-фай-


10.5. GLUT в среде BORLAND C++ BUILDER 2006
ствия:

141

Для создания приложения надо выполнить следующие дей-



Создание проекта: для этого надо выбрать File Other Console Wizard, OK.




New

В появившемся окне выбрать Source Typ e С++, Console Application, сбросить опции ?Use VCL?, ?Use CLX?, ?Multi Threaded?. Нажать ОК. Текст программы можно либо разместить в созданном текстовом файле, либо удалить его из проекта (Pro ject или *.cpp в проект (выбрав Pro ject Remove From Pro ject) и добавить файл с расширением *.c







Add To Pro ject).

Сохраните созданный проект в желаемом каталоге (выбрав File Save All).



Подключить к проекту библиотеку GLUT. Для этого надо выбрать Pro ject Add To Pro ject и добавить файл glut32.lib



Для компиляции выбрать Pro ject ния Run Run.





Build . . . , для выполне-

Когда программа готова, рекомендуется перекомпилировать ее в режиме ?Release? для оптимизации по быстродействию и объему. Для этого сначала надо выбрать Pro ject Compiler и нажать кнопку ?Release?. Options





10.5. GLUT в среде Borland C++ Builder 2006
Перед вать ги началом glut.h, работы glut32.lib, необходимо glut32.dll в скопирокаталофайлы Borland\BDS\4.0\Include\Gl, Borland\BDS\4.0\Lib,


142

Глава 10. OPENGL-приложения с помощью GLUT

Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, op engl32.lib, glu32.lib, op engl32.dll, glu32.dll, которые обычно входят в состав Borland C++ и Windows. При этом надо учитывать, что оригинальные (для Microsoft Visual C++) версии файла glut32.lib c Borland C++ Builder 6 работать не будут, и следует использовать только совместимую версию. Чтобы создать такую версию, надо использовать стандартную программу 'implib', которая находится в каталоге Borland\BDS\4.0\Bin. Для этого в командной строке надо выполнить команду

implib glut32.lib
ла.

glut32.dll

которая создает нужный lib-файл из соответствующего dll-файДля создания приложения надо выполнить следующие действия:



Создание проекта: для этого надо выбрать File Other Console Application, OK.




New

В появившемся окне выбрать Source Typ e ?С++?, ?Console Application?, сбросить опции ?Use VCL?, ?Multi Threaded?. Нажать ОК. Текст программы можно либо разместить в созданном текстовом файле, либо удалить его из проекта (Pro ject или *.cpp в проект (выбрав Pro ject Remove From Pro ject) и добавить файл с расширением *.c







Add To Pro ject).

Сохраните созданный проект в желаемом каталоге (выбрав File Save All).



Подключить к проекту библиотеку GLUT. Для этого надо выбрать Pro ject Add To Pro ject и добавить файл glut32.lib




10.5. GLUT в среде BORLAND C++ BUILDER 2006

143



Для компиляции выбрать Pro ject ния Run Run.





Build . . . , для выполне-

Когда программа готова, рекомендуется перекомпилировать ее в режиме ?Release? для оптимизации по быстродействию и объему. Для этого надо выбрать Pro ject Build Congurations и в списке ?Conguration name? выбрать ?Release Build?.





Глава 11.

Использование Op enGL в MFC и VCL
Далее будем рассматривать принципы построение оконного приложения Windows с поддержкой Op enGL при помощи возможностей библиотек MFC (Microsoft Foundation Classes) и VCL (Visual Comp onent Library). Поскольку Windows является многооконной операционной системой, основная задача приложения на этапе инициализации ?привязать? команды Op enGL к конкретному окну и создать для этого окна все вспомогательные буферы (буфер кадра, буфер глубины и т.п.). Сама библиотека не содержит средств для этого, поэтому каждая операционная система, поддерживающая Op enGL, предоставляет свои. Библиотека GLUT представляет унифицированный интерфейс для доступа к этой функциональности, однако платой за унификацию является достаточно скромные возможности построения графического интерфейса пользователя, реализованные в GLUT. Для создания приложений с развитым интерфейсом необходимо применять средства конкретной операционной системы для работы с Op enGL. Для инициализации и работы с Op enGL в Windows необхо145


146

Глава 11. Использование OPENGL в MFC и VCL

димо выполнить следующие шаги: 1) инициализация (при создании окна); а) получение и установка контекста графического устройства (см. п.11.1); б) установка пиксельного формата (п.11.2); в) получение и установка контекста рисования (п.11.3); 2) рисование с помощью Op enGL в окне; 3) освобождение контекстов (при удалении окна).

11.1. Контекст устройства
Контекст устройства (device context) важный элемент графики в среде ОС Windows. Контекст устройства указывает место отображения графических команд. Контекстом может быть окно программы на экране, принтер, или другое устройство, поддерживающее графический вывод. Идентификатор контекста устройства это числовое значение, знание которого позволяет направить графический вывод в нужный контекст. Перед началом рисования необходимо получить это числовое значение, а после рисования нужно контекст освободить, т.е. вернуть используемые ресурсы в систему. Несоблюдение этого правила чревато такими последствиями как утечки памяти и прекращение нормальной работы программы. Поскольку нашей задачей является рисование в окне, конокна

hDC можно получить по идентификатору hWnd: HWND hWnd = <к о д п о л у ч е н и е и д е н т и ф и к а т о р а о к н а > ; HDC hDC = GetDC ( hWnd ) ;
текст устройства Для освобождения контекста используется команда

ReleaseDC

:

R e l e a s e D C ( hWnd , hDC ) ;


11.2. Установка формата пикселей

147

11.2. Установка формата пикселей
После получения контекста устройств нужно установить формат пикселей (pixel format) контекста. Это нужно для того, чтобы сообщить операционной системе, какие ресурсы необходимо выделить для данного контекста. Формат пикселей указывает, какие возможности Op enGL мы будем использовать: двойной буфер, буфер маски, буфер глубины, формат цвета и т.д. Чтобы установить формат пикселя, нужно заполнить структуру

PIXELFORMATDESCRIPTOR

и передать ее в текущий кон-

текст:

PIXELFORMATDESCRIPTOR p f d ;
/ / з а п о л н я е м структуру

Z e r o M e m o r y (& p f d , s i z e o f ( p f d ) ) ; pfd . nSize = sizeof ( pfd ) ; pfd . nVersion = 1 ;

/ / о б н у л я е м в с е т о л ь к о что с о з д а н н о й структуры ;

/ / ф л а г и показывают , что мы б у д е м и с п о л ь з о в а т ь / / дублирующую б у ф е р и з а ц и ю OpenGL в этом о к н е

/ / п о л н о ц в е т н ы й б у ф е р ц в е т а ( 8 бит н а к а н а л ) / / з а п р а ш и в а е м 1 6 бит н а п и к с е л ь д л я б у ф е р а г л у б и н ы

P f d . d w F l a g s = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ; p f d . i P i x e l T y p e = PFD_TYPE_RGBA ; pfd . c C o l o r B i t s = 2 4 ; pfd . cDepthBits pfd . iLayerType int iFormat = SetPixelFormat

= 16; = PFD_MAIN_PLANE ; C h o o s e P i x e l F o r m a t ( hDC , &p f d ) ; ( hDC , i F o r m a t , &p f d ) ;

Рассмотрим подробнее функции, которые используются для установки формата пикселя:

int ChoosePixelFormat (

HDC h d c , CONST PIXELFORMATDESCRIPTOR *

ppfd ) ;


148

Глава 11. Использование OPENGL в MFC и VCL
Эта функция позволяет по контексту графического устрой-

ства найти пиксельный формат, максимально удовлетворяющий нашим требованиям, и возвращает его дескриптор. Например, если запрошен 24-битный буфер цвета, а контекст графического устройства предоставляет только 8-битный буфер, то функция возвратит формат пикселя с 8-битным буфером. Функция

SetPixelFormat

устанавливает формат пикселя в кон-

текст графического устройства:

BOOL S e t P i x e l F o r m a t ( HDC h d c , i n t i P i x e l F o r m a t , CONST PIXELFORMATDESCRIPTOR *

ppfd ) ;

Поскольку мы используем контекст графического устройства с двойным буфером, Op enGL-рисование в контекст происходит в невидимое на экране место в памяти. Это необходимо для предотвращения мерцания. Для того, чтобы изображение появилось на экране, нужно вызвать следующую функцию:

S w a p B u f f e r s ( hDC ) ;

11.3. Контекст рисования (render context)
Контекст рисования определяет в какой контекст устройства будут направляться команды Op enGL. Например, если в программе есть несколько окон Op enGL, то перед вызовом команд Op enGL необходимо указать окно, в которое будут направлены эти команды. С контекстом рисования ассоциировано текущее состояние Op enGL, текстуры, дисплейные списки и т.п. Создание контекста рисования

hRC

:

HGLRC hRC ; hRC = w g l C r e a t e C o n t e x t ( hDC ) ;
Перед использованием контекста необходимо сделать его текущим:


11.4. Класс GLRC
w g l M a k e C u r r e n t ( hDC , hRC ) ;

149

Далее можно свободно использовать команды Op enGL, не забывая вызывать

SwapBuers

после окончания рисования кадра.

После использования контекста рисования его нужно освободить (обычно перед освобождением соответствующего контекста устройства):

w g l D e l e t e C o n t e x t ( hRC ) ;

11.4. Класс GLRC
В п.Б.5 приведен пример класса

GLRC

, реализующий пере-

численные операции. Цикл инициализации и рисования с использованием этого класса выглядит следующим образом:

GLRC* m_pGLRC ; ... m_pGLRC bool r e s if (! res Error ( ..

// 1 . инициализация о кн а

= new GLRC( hWnd ) ; = m_pGLRC >C r e a t e ( ) ; - ) " Невозможно с о з д а т ь к о н т е к с т OpenGL" ) ;

// 2 . р и с о в а н и е / / ( о б ы ч н о в о б р а б о т ч и к а х события WM_PAINT) b o o l r e s = m_pGLRC >M a k e C u r r e n t ( ) ; -

if (! res )

E r r o r ( " Н е в о з м о ж н о с д е л а т ь к о н т е к с т текущим " ) ;

/ / к о м а н д ы OpenGL

g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ...

m_pGLRC >S w a p B u f f e r s ( ) ; -

// завершение к а д р а


150

Глава 11. Использование OPENGL в MFC и VCL

/ / 3 . уничтожение о к н а // ( о б ы ч н о в о б р а б о т ч и к а х события WM_DESTROY) m_pGLRC >D e s t r o y ( ) ; -

d e l e t e m_pGLRC ;

11.5. Использование OpenGL c MFC
Если при создании Windows-приложения используется библиотека MFC, то необходимо встроить инициализацию, освобождение контекстов и рисование Op enGL в различные обработчики унаследованных классов MFC. Данная книга не является руководством по программированию с использованием MFC, поэтому ограничимся советами по использованию Op enGL с этой библиотекой:



Код инициализации и рисования теперь должен находиться в методах (или вызываться из этих методов) класса, унаследованного от класса

CWnd

напрямую или косвенно.

Для инициализации Op enGL лучше всего использовать метод или

OnCreate OnTimer

, для рисования

OnPaint, OnUpdate, OnDraw

(это зависит от разных факторов, например,

от какого именно класса унаследован класс Op enGL-окна и что именно изображается). Для предотвращения мерцания необходимо перегрузить обработчик сообщения

WM_ERASEBKGND

, иначе Windows

будет заливать фон окна перед вызовом обработчика Для освобождения подойдет обработчик обработки изменений размера окна

OnPaint.

OnDestroy OnSize.

, а для

Получить идентификатор окна можно с помощью метода

CWnd::GetSafeHwnd.


11.5. Использование OPENGL C MFC
при помощи Op enGL.

151

Пример класса окна, рисование в которое осуществляется

{

c l a s s OpenGLWindow : p u b l i c CWnd
OpenGLWindow ( ) ;

public :
...

/ / открытые ч л е н ы к л а с с а

private :
... f f f f x x x x

/ / закрытые ч л е н ы к л а с с а / / с и г н а т у р ы этих м е т о д о в о п р е д е л е н ы з а р а н е е MFC / / и должны в ы г л я д е т ь и м е н н о так

a a a a

_ _ _ _

m m m m

s s s s

g g g g

i n t On BOOL O void O void O

C r e a t e (LPCREATESTRUCT l p C r e a t e S t r u c t ) ; n E r a s e B k g n d (CDC* pDC ) ; nPaint ( ) ; nDestroy ( ) ;

DECLARE_MESSAGE_MAP( ) GLRC* m_pGLRC ;

/ / о б ъ я в л е н и е кар ты с о о б щ е н и й W i n d o w s / / к л а с с д л я х р а н е н и я к о н т е к с т о в OpenGL

};

Реализация методов:

OpenGLWindow : : OpenGLWindow ( ) : m_pGLRC( NULL ) { } BEGIN_MESSAGE_MAP( OpenGLWindow , CWnd) ON_WM_CREATE( ) ON_WM_PAINT( )
/ / стандартные м а к р о с ы MFC / / з а п о л н е н и е ка рты с о о б щ е н и й

/ / конструктор


152

Глава 11. Использование OPENGL в MFC и VCL

ON_WM_DESTROY( ) ON_WM_ERASEBKGND( ) END_MESSAGE_MAP( ) a f x _ m s g i n t OpenGLWindow : : O n C r e a t e ( LPCREATESTRUCT l p C r e a t e S t r u c t ) {
/ / в этом методе р е а л и з у е м и н и ц и а л и з а ц и ю

m_pGLRC = new GLRC( G e t S a f e H w n d ( ) ) ; b o o l r e s = m_pGLRC >C r e a t e ( ) ; - if (! res ) r e t u r n FALSE ; }

r e t u r n CWnd : : O n C r e a t e ( l p C r e a t e S t r u c t ) ;

a f x _ m s g BOOL OpenGLWindow : : O n E r a s e B k g n d (CDC* pDC ) { r e t u r n FALSE ; } a f x _ m s g v o i d OpenGLWindow : : O n P a i n t ( ) { CWnd : : O n P a i n t ( ) ; m_glRC->M a k e C u r r e n t ( ) ; g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; <методы р и с о в а н и я OpenGL>
/ / р и с у е м то , что хотим н а р и с о в а т ь / / д е л а е м текущим // з д е с ь рисуем

/ / запрещаем з а л и в к у фона


11.6. Использование OPENGL C VCL
} m_glRC->S w a p B u f f e r s ( ) ;

153

a f x _ m s g v o i d OpenGLWindow : : O n D e s t r o y ( ) { m_glRC->D e s t r o y ( ) ; d e l e t e m_glRC ; } CWnd : : O n D e s t r o y ( ) ;

// з д е с ь происходит освобождение р е с у р с о в

11.6. Использование OpenGL c VCL
Использование Op enGL с VCL другой популярной библиотекой для разработки Windows-приложений, отличается от предыдущего примера только деталям и названиями классов. Вот пример минимального кода на С++, который добавит Op enGL к форме (окну) VCL:

{

c l a s s OpenGLForm : p u b l i c TForm
_ _ f a s t c a l l OpenGLForm ( TComponent * o w n e r ) ;

public :
...

/ / открытые ч л е н ы к л а с с а

private :

GLRC* m_pGLRC ; ... published :

/ / закрытые ч л е н ы к л а с с а / / контекст у с т р о й с т в а о к н а / / с и г н а т у р ы этих м е т о д о в о п р е д е л е н ы з а р а н е е

void _ _ f a s t c a l l FormCreate ( T O b j e c t * s e n d e r ) ; void _ _ f a s t c a l l Fo rm D es tr oy ( T O b j e c t * s e n d e r ) ;


154

Глава 11. Использование OPENGL в MFC и VCL
* sender ) ;

};

void _ _ f a s t c a l l FormPaint ( T O b j e c t

_ _ f a s t c a l l OpenGLForm : : OpenGLForm ( TComponent * o w n e r ) : TForm ( o w n e r ) , m_pGLRC( NULL ) { }

/ / конструктор

v o i d _ _ f a s t c a l l OpenGLForm : : F o r m C r e a t e (
{ TObject * s e n d e r ) m_pGLRC = new GLRC( H a n d l e ) ; b o o l r e s = m_pGLRC >C r e a t e ( ) ; - assert ( res );

/ / в этом методе р е а л и з у е м и н и ц и а л и з а ц и ю

}

v o i d _ _ f a s t c a l l OpenGLForm : : F o r m P a i n t (
{ TObject * s e n d e r )
/ / д е л а е м текущим m_glRC->M a k e C u r r e n t ( ) ;

// з д е с ь рисуем

g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; <методы р и с о в а н и я OpenGL> } m_glRC->S w a p B u f f e r s ( ) ;
/ / р и с у е м то , что хотим н а р и с о в а т ь

// з д е с ь происходит деинициализация


11.6. Использование OPENGL C VCL
{

155

v o i d _ _ f a s t c a l l OpenGLForm : : F o r m D e s t r o y ( )
m_glRC->D e s t r o y ( ) ; d e l e t e m_glRC ;

}



Глава 12.

Op enGL в .NET
В этом разделе рассматривается построение оконного приложения с поддержкой Op enGL на платформе Microsoft .NET. Несмотря на то, что Op enGL не имеет встроенной поддержки в .NET, в настоящее время существует достаточно много решений, позволяющих подключать Op enGL к .NET-программам. Мы рассмотрим работу с одной из них свободно-распространяемой библиотекой Tao Framework. Tao Framеwork (http://www.taoframework.com) реализует промежуточный уровень между .NET приложением и различными Win32-библиотеками, в частности GL, GLU, GLUT, WGL.

12.1. GLUT в среде Microsoft Visual C# 2005
Простейшим способом создания Op enGL-приложения с среде .NET можно считать использование библиотеки GLUT, доступной через .NET-компоненту Tao.FreeGlut. Далее приводятся шаги, необходимые для создания консольного .NET-приложения в среде Microsoft Visual C# 2005 на C# с GLUT и Op enGL: 157


158

Глава 12. OPENGL в .NET



Убедиться, что на машине установлен GLUT (glut32.dll лежит в Windows\System32).

Создание проекта консольного приложения: File Pro jects Visual C# Windows брать имя проекта, OK.







Console Application, на-


New

Добавление Tao к проекту: Pro ject

найти в списке ?Tao Framework Op enGL Binding For .NET? и ?Tao Framework FreeGLUT Binding For .NET?, выделить оба, ОК. Если компонент нет в списке, необходимо найти их в инсталляционном каталоге библиотеки Tao Framework и добавить через вкладку Browse.



Add Reference



.NET,

Программирование с использование GLUT и Op enGL в .NET на C# практически не отличается от варианта для Win32 и C++. Ниже приведен пример простой программы, аналогичной примеру из п.2.5: Программа 12.1. Простой пример Op enGL в C#.

u s i n g Tao . F r e e G l u t ; u s i n g Tao . O p e n G l ; n am e s pa c e g l _ g l u t _ n e t
{

{

c l a s s Program p r i v a t e s t a t i c i n t Width = 5 1 2 ; private s t a t i c int Height = 5 1 2 ; public const i n t C u b e S i z e = 2 0 0 ;
{

s t a t i c void D i s p l a y ( ) i n t l e f t , r i g h t , top , bottom ;


12.1. GLUT в среде MICROSOFT VISUAL C# 2005
l e f t = ( Width - right = l e f t + bottom = ( H e i g h t o p = bottom + Cu Cub t- Cub be eS C eS Size ) / 2 ; ize ; ubeSize ) / 2 ; ize ;

159

Gl . g l C l e a r C o l o r ( 0 . 7 f , 0 . 7 f , 0 . 7 f , 1 ) ; G l . g l C l e a r ( G l . GL_COLOR_BUFFER_BIT ) ; G G G G G G G } { l l l l l l l . . . . . . . g g g g g g g lColor3ub l B e g i n ( Gl lVertex2f lVertex2f lVertex2f lVertex2f lEnd ( ) ; (255 , 0 , 0 ) ; . GL_QUADS ) ; ( l e f t , bottom ) ; ( l e f t , top ) ; ( r i g h t , top ) ; ( r i g h t , bottom ) ;

Gl . g l F i n i s h ( ) ;

s t a t i c void R e s h a p e ( i n t w , i n t h )
Width = w ; Height = h ; Gl . g l V i e w p o r t ( 0 , 0 , w , h ) ; G l . g l M a t r i x M o d e ( G l . GL_PROJECTION ) ; Gl . g l L o a d I d e n t i t y ( ) ; Gl . g l O r t h o ( 0 , w , 0 , h , - 1 . 0 , 1 . 0 ) ; G l . g l M a t r i x M o d e ( G l . GL_MODELVIEW ) ; Gl . g l L o a d I d e n t i t y ( ) ;

}

s t a t i c void Keyboard ( b y t e key , i n t x , i n t y )


160

Глава 12. OPENGL в .NET
{

c o n s t i n t ESCAPE = 2 7 ; i f ( k e y == ESCAPE)
Glut . glutLeaveMainLoop ( ) ;

}

{

s t a t i c v o i d Main ( s t r i n g [ ] a r g s )
G G G G l l l l u u u u t t t t . . . . glutInit (); g l u t I n i t D i s p l a y M o d e ( G l u t . GLUT_RGB ) ; g l u t I n i t W i n d o w S i z e ( Width , H e i g h t ) ; g l u t C r e a t e W i n d o w ( " Red s q u a r e e x a m p l e " ) ;

Glut . g l u t D i s p l a y F u n c ( D i s p l a y ) ; Glut . glutReshapeFunc ( Reshape ) ; G lu t . g l u t K e y b o a r d F u n c ( Keyboard ) ; } Glut . glutMainLoop ( ) ;

}

}

Обратите внимание, что все команды и константы GL, GLU и GLUT находятся в пространствах имен ственно.

Gl, Glu

и

Glut

, соответ-

12.2. Использование OpenGL в WindowsForms
Op enGL в WindowsForms требует инициализации, аналогичной рассмотренной для библиотек MFC и VCL (см. п.11). В Tao Framework уже реализован простой класс окна Op enGL

Tao.Platform.Windows.SimpleOpenGlControl

.

Рассмотрим последовательность действий, необходимую для


12.2. Использование OPENGL в WINDOWSFORMS
поддержкой Op enGL:

161

создания простого оконного приложения в WindowsForms и с



Создание проекта приложения: File C# Windows та, OK.





Windows Application, набрать имя проек-


New

Pro jects



Visual

Добавление Tao к проекту: Pro ject

найти в списке ?Tao Framework Op enGL Binding For .NET? и ?Tao Framework Windows Platform API Binding For .NET?, выделить оба, ОК. Если компонент нет в списке, необходимо найти их в инсталляционном каталоге библиотеки Tao Framework и добавить через вкладку Browse. Чтобы удобно создать окно Op enGL, необходимо добавить соответствующий объект на панель инструментов. Для этого нужно в контекстном меню панели ?To olb ox? выбрать пункт ?Cho ose Items...?, в появившемся списке найти ?SimpleOp enGLControl?, поставить галочку около него, ОК. Добавление окна Op enGL на форму: на панели ?To olb ox? найдите ?SimpleOp enGLControl? и перетащите на форму приложения. Окно должно заполняться черным цветом. Инициализация Op enGL: в конструкторе формы после вызова



Add Reference



.NET,





InitializeComponent() добавить вызов функции контекста simpleOp enGlControl1.InitializeContexts(). Paint
окна Op enGL (не путать с

создания

Функции рисования Op enGL можно добавлять в обработчик события

Paint

формы).



Часть IV

Приложения

163



Приложение А.

Примитивы библиотек GLU и GLUT
Рассмотрим стандартные команды построения примитивов, которые реализованы в библиотеках GLU и GLUT. Чтобы построить примитив из библиотеки GLU, надо сначала создать указатель на quadric-объект с помощью команды

gluNewQuadric(), а затем вызвать gluCylinder(), gluDisk(), gluPartialDisk ()
отдельно:

одну из команд

gluSphere()

,

. Рассмотрим эти команды

void g l u S p h e r e ( GLUquadricObj
radius

* q o b j , GLdouble r a d i u s , GLint s l i c e s , GLint s t a c k s )

Эта функция строит сферу с центром в начале координат и радиусом . При этом число разбиений сферы вокруг оси z задается параметром

slices L L L L

, а вдоль оси z параметром

stacks

.

void g l u C y l i n d e r ( GLUquadricObj
G G G G dou dou dou int bl bl bl s e e e t

* qobj , baseRadius , topRadius , h e i g h t , GLint s l i c e s , acks )

165


166

Приложение А. Примитивы библиотек GLU и GLUT
Данная функция строит цилиндр без оснований (кольцо),

продольная ось параллельна оси z, заднее основание имеет радиус

baseRadius

, и расположено в плоскости

z=0

основание имеет радиус

topRadius slices

, переднее

и расположено в плоскости и

z = heig ht

. Если задать один из радиусов равным нулю, то будет

построен конус. Параметры

stacks

имеют аналогичный

смысл, что и в предыдущей команде.

void g l u D i s k ( GLUquadricObj
G G G G L L L L dou dou int int ble ble sl lo

* qobj , innerRadius , outerRadius , ices , ops )

Функция строит плоский диск (круг) с центром в начале координат и радиусом усом

outerRadius

. Если значение

innerRadius

отлич-

но от нуля, то в центре диска будет находиться отверстие ради-

innerRadius

. Параметр

вокруг оси z, а параметр перпендикулярных оси z.

slices loops

задает число разбиений диска число концентрических колец,

void g l u P a r t i a l D i s k ( GLUquadricObj
G G G G G G L L L L L L dou dou int int dou dou ble ble sli loo ble ble

* qobj innerRadiu outerRadiu ces , ps , startAngle sweepAngle

, s, s, , );

Отличие этой команды от предыдущей заключается в том, что она строит сектор круга, начальный и конечный углы которого отсчитываются против часовой стрелки от положительного направления оси y и задаются параметрами . Углы измеряются в градусах.

sweepAngle

startAngle

и

Команды, проводящие построение примитивов из библиотеки GLUT, реализованы через стандартные примитивы Op enGL


167

и GLU. Для построения нужного примитива достаточно произвести вызов соответствующей команды.

void g l u t S o l i d S p h e r e void g l u t W i r e S p h e r e

( GLdouble r a d i u s , GLint s l i c e s , GLint s t a c k s ) ( GLdouble r a d i u s , GLint s l i c e s , GLint s t a c k s )
строит сферу, а

Команда

glutSolidSphere()

glutWireSphere()



каркас сферы радиусом radius. Остальные параметры те же, что и в предыдущих командах.

void g l u t S o l i d C u b e ( GLdouble s i z e ) void g l u t W i r e C u b e ( GLdouble s i z e )
Команды строят куб или каркас куба с центром в начале координат и длиной ребра size.

void g l u t S o l i d C o n e void g l u t W i r e C o n e

( GLdouble b a s GLint s l i c e s , ( GLdouble b a s e GLint s l i c e s ,

e , GLdouble GLint s t a c , GLdouble GLint s t a c k

height , ks ) height , s) height
и

Эти команды строят конус или его каркас высотой ние находится в плоскости

радиусом основания base, расположенный вдоль оси z. Основа-

z = 0.

void g l u t S o l i d T o r u s ( GLdouble i n n e r R a d i u s , void g l u t W i r e T o r u s
G G G (G G G G L L L L L L L dou int int dou dou int int bl n r bl bl n r e si in e e si in out des gs ) inn out des gs ) erRadius , ,

erRadius , erRadius , ,
z = 0.

Эти команды строят тор или его каркас в плоскости

Внутренний и внешний радиусы контролируются параметрами


168

Приложение А. Примитивы библиотек GLU и GLUT
и

innerRadius

outerRadius

. Параметр

nsides

задает число сторон

в кольцах, составляющих ортогональное сечение тора, а число радиальных разбиений тора.

rings



void g l u t S o l i d T e t r a h e d r o n ( void ) void g l u t W i r e T e t r a h e d r o n ( void )
Эти команды строят тетраэдр (правильную треугольную пирамиду) или его каркас, при этом радиус описанной сферы вокруг него равен 1.

void g l u t S o l i d O c t a h e d r o n ( void ) void g l u t W i r e O c t a h e d r o n ( void )
Эти команды строят октаэдр или его каркас, радиус описанной вокруг него сферы равен 1.

void g l u t S o l i d D o d e c a h e d r o n ( void ) void g l u t W i r e D o d e c a h e d r o n ( void )
Эти команды строят додекаэдр или его каркас, радиус описанной вокруг него сферы равен квадратному корню из трех.

void g l u t S o l i d I c o s a h e d r o n ( void ) void g l u t W i r e I c o s a h e d r o n ( void )
Эти команды строят икосаэдр или его каркас, радиус описанной вокруг него сферы равен 1. Правильное построение перечисленных примитивов возможно при удалении невидимых линии и поверхностей, для чего надо включить соответствующий режим вызовом команды

glEnable(GL_DEPTH_TEST)

.


Приложение Б.

Демонстрационные программы

Б.1. Пример 1: Простое GLUT-приложение
Этот простой пример предназначен для демонстрации структуры GLUT-приложения и простейших основ Op enGL. Результатом работы программы является случайный набор цветных прямоугольников, который меняется при нажатии левой кнопки мыши. С помощью правой кнопки мыши можно менять режим заливки прямоугольников. Программа Б.1. Простой пример Op enGL.

#i n c l u d e < s t d l i b . h> #i n c l u d e < g l \ g l u t . h> #i f d e f random #undef random #e n d i f #d e f i n e random (m) ( f l o a t ) r a n d ( ) *m/RAND_MAX
169


170

Приложение Б. Демонстрационные программы

/ / ширина и в ы с о т а о к н а

// число прямоугольников в о к н е // с заполнением ?

G L i n t Width = 5 1 2 , H e i g h t = 5 1 2 ;

int

Times = 1 0 0 ; FillFlag

int

= 1;

long

Seed = 0 ;

{

void DrawRect ( f l o a t x1 , f l o a t y1 , f l o a t x2 , f l o a t y2 , int F i l l F l a g )
g g g g g g lBeg lVer lVer lVer lVer lEnd in te te te te () ( x x x x ; Fi 2f 2f 2f 2f l ( ( ( ( lF x1 x2 x2 x1 l , , , , ag y y y y 1 1 2 2 ? ) ) ) ) ; ; ; ;

/ / ф у н к ц и я отображает п р я м о у г о л ь н и к

GL_QUADS : GL_LINE_LOOP ) ;

}

{

void D i s p l a y ( void )

// управляет всем выводом на э к р а н

int i ; f l o a t x1 , y1 , x2 , y 2 ; float r , g , b ;
srand ( Seed ) ; glClearColor (0 , 0 , 0 , 1); g l C l e a r (GL_COLOR_BUFFER_BIT ) ;

f o r ( i = 0 ; i < T i m e s ; i ++ ) {
r = random ( 1 ) ; g = random ( 1 ) ;


Б.1. Пример 1: Простое GLUT-приложение
b = random ( 1 ) ; glColor3f ( r , g , b ); x1 y1 x2 y2 Dr = = = = aw rando rando rando rando Rect ( m m m m x ( ( ( ( 1 1 1 1 1 , ) ) ) ) Widt Heig Widt Heig y1 , x2 ,
* * * *

171

h h h h

} }

; t; ; t; y2 , F i l l F l a g ) ;

glFinish ();

{

void R e s h a p e ( GLint w , GLint h )
Width = w ; Height = h ; g l V i e w p o r t ( 0 , 0 , w, h ) ;

/ / Вызывается п р и и з м е н е н и и р а з м е р о в о к н а

g l M a t r i x M o d e (GL_PROJECTION ) ; glLoadIdentity ( ) ; glOrtho ( 0 , w, 0 , h , -1.0 , 1 . 0 ) ; g l M a t r i x M o d e (GL_MODELVIEW ) ; glLoadIdentity ( ) ;

}

{

v o i d Mouse ( i n t b u t t o n , i n t s t a t e , int x , int y ) i f ( s t a t e == GLUT_DOWN ) { switch ( b u t t o n ) { c a s e GLUT_LEFT_BUTTON :

/ / Обрабатывает с о о б щ е н и я от мыши

S e e d = r a n d o m (RAND_MAX) ;


172

Приложение Б. Демонстрационные программы
break ; c a s e GLUT_RIGHT_BUTTON :
} glutPostRedisplay ( ) ; FillFlag = ! FillFlag ;

break ;

}

}

{

void K e y b o a r d ( unsigned char k e y , i n t x , i n t y ) c o n s t c h a r ESCAPE = ' \ 0 3 3 ' ; i f ( k e y == ESCAPE )
exit (0);

/ / Обрабатывает с о о б щ е н и я от к л а в и а т у р ы

} {

void main ( i n t a r g c , char
g l u t I n i t (& a r g c , a r glutInitDisplayMod glutInitWindowSize glutCreateWindow ( " g g g g l l l l utDisplayFu utReshapeFu utKeyboardF utMouseFunc n n u (

* argv [ ] )

gv ) ; e (GLUT_RGB ) ; ( Width , H e i g h t ) ; R e c t d r a w e x a m p l e (RGB) " ) ;

c ( Display ) ; c ( Reshape ) ; n c ( Keyboard ) ; Mouse ) ;

}

glutMainLoop ( ) ;


Б.2. Пример 2: Модель освещения OPENGL

173

Рис. Б.1. Результат работы программы Б.1. Слева режим заполнения, справа режим контуров.

Б.2. Пример 2: Модель освещения OpenGL
Программа предназначена для демонстрации модели освещения Op enGL на примере простой сцены, состоящей из тора, конуса и шара. Объектам назначаются разные материалы. В сцене присутствует точечный источник света. Программа Б.2. Модель освещения Op enGL.

#i n c l u d e < s t d l i b . h> #i n c l u d e
/ / параметры м а т е р и а л а тора

f f f f

l l l l

o o o o

a a a a

t t t t

mat1_dif [ ] = { 0 mat1_amb [ ] = { mat1_spec [ ] = { mat1_shinines

.8 f , 0.2 f 0.6 f s =0.

0 , , 5

. 0 0 f

8 f ,0.0 f }; .2 f ,0.2 f }; .6 f ,0.6 f }; *128;

/ / параметры м а т е р и а л а к о н у с а

f l o a t mat2_dif [ ] = { 0 . 0 f , 0 . 0 f , 0 . 8 f } ; f l o a t mat2_amb [ ] = { 0 . 2 f , 0 . 2 f , 0 . 2 f } ; f l o a t mat2_spec [ ] = { 0 . 6 f , 0 . 6 f , 0 . 6 f } ;


174

Приложение Б. Демонстрационные программы

f l o a t m a t 2 _ s h i n i n e s s =0.7 f * 1 2 8 ;
/ / параметры м а т е р и а л а шара

f f f f

l l l l

o o o o

a a a a

t t t t

mat3_dif [ ] = { 0 mat3_amb [ ] = { mat3_spec [ ] = { mat3_shinines

.9 f , 0.2 f 0.6 f s =0.

0 , , 1

. 0 0 f

2 f ,0.0 f }; .2 f ,0.2 f }; .6 f ,0.6 f }; *128;

{

void i n i t ( void )
G G G G L L L L f f f f l l l l o o o o a a a a t t t t l l l l i i i i

/ / И н и ц и а л и з и р у е м параметры м а т е р и а л о в и / / источника света

ght_ambient [ ght_diffuse [ ght_specular ght_position

] ] [ [

={ ={ ]= ]=

0.0 1.0 { 1. { 1.

, , 0 0

0.0 1.0 , 1. , 1.

, , 0 0

0.0 1.0 , 1. , 1.

, , 0 0

1.0 1.0 , 1. , 0.

}; }; 0 }; 0 };

/ * у с т а н а в л и в а е м параметры и с т о ч н и к а с в е т а * /

g l L i g h t f v ( GL_LIGHT0 light_ambient ) ; g l L i g h t f v ( GL_LIGHT0 light_diffuse ); g l L i g h t f v ( GL_LIGHT0 light_specular ); g l L i g h t f v ( GL_LIGHT0 light_position );

, GL_AMBIENT, , GL_DIFFUSE ,

, GL_SPECULAR, , GL_POSITION ,

/ * включаем о с в е щ е н и е и источник с в е т а * / / * в к л ю ч а е м z -б у ф е р * /

g l E n a b l e ( GL_LIGHTING ) ; g l E n a b l e ( GL_LIGHT0 ) ;

g l E n a b l e (GL_DEPTH_TEST ) ;

}
/ / Функция в ы з ы в а е т с я п р и н е о б х о д и м о с т и / / п е р е р и с о в к и изображения .


Б.2. Пример 2: Модель освещения OPENGL
{

175

void d i s p l a y ( void )

/ / В н е й осуществляется в е с ь в ы в о д геометрии . / * очищаем б у ф е р к а д р а и б у ф е р г л у б и н ы * /

g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;

glPushMatrix ( ) ; glRotatef (20.0 , 1.0 , 0.0 , 0 . 0 ) ;
/ * отображаем тор * /

glMaterialfv mat1_amb ) ; glMaterialfv mat1_dif ) ; glMaterialfv mat1_spec ) glMaterialf mat1_shini lPushMatrix lTranslatef lRotatef (9 lutSolidTor lPopMatrix

(GL_FRONT, GL_AMBIENT, (GL_FRONT, GL_DIFFUSE ,

;

(GL_FRONT, GL_SPECULAR,

(GL_FRONT, GL_SHININESS , ness ) ;
-0.75 , 0 . 5 , 0 . 0 ) ;

g g g g g

( ( 0. us ()

);

0 , 1.0 , 0.0 , 0.0); ( 0 . 2 7 5 , 0.85 , 15 , 1 5 ) ; ;

/ * отображаем к о н у с * /

glMaterialfv mat2_amb ) ; glMaterialfv mat2_dif ) ; glMaterialfv mat2_spec ) glMaterialf mat2_shini

(GL_FRONT, GL_AMBIENT, (GL_FRONT, GL_DIFFUSE ,

;

(GL_FRONT, GL_SPECULAR,

(GL_FRONT, GL_SHININESS , ness ) ;

glPushMatrix ( ) ;


176

Приложение Б. Демонстрационные программы
lTranslatef lRotatef (2 lutSolidCon lPopMatrix ( -0.75 , -0.5 , 0 . 0 ) ; 70.0 , 1.0 , 0.0 , 0.0); e ( 1 . 0 , 2 . 0 , 15 , 1 5 ) ; (); (GL_FRONT, GL_AMBIENT, (GL_FRONT, GL_DIFFUSE , ; (GL_FRONT, GL_SPECULAR,

g g g g

/ * отображаем шар * /

glMaterialfv mat3_amb ) ; glMaterialfv mat3_dif ) ; glMaterialfv mat3_spec ) glMaterialf mat3_shini lPushMatrix lTranslatef lutSolidSph lPopMatrix

(GL_FRONT, GL_SHININESS , ness ) ; ); 0 . 7 5 , 0.0 , -1.0); e ( 1 . 0 , 15 , 1 5 ) ; ;

g g g g

( ( er ()

/ * выводим с ц е н у н а э к р а н * /

glPopMatrix ( ) ; glFlush ( ) ;

}

{

void r e s h a p e ( i n t w , i n t h )

/ / Вызывается п р и и з м е н е н и и п о л ь з о в а т е л е м // размеров окна // устанавливаем р а з м е р области в ы в о д а / / равным р а з м е р у о к н а / / з а д а е м матрицу п р о е к ц и и с учетом // размеров окна

g l V i e w p o r t ( 0 , 0 , ( G L s i z e i ) w, ( G L s i z e i ) h ) ;

g l M a t r i x M o d e (GL_PROJECTION ) ; glLoadIdentity ( ) ;


Б.2. Пример 2: Модель освещения OPENGL
gluPerspective ( 40.0 ,
// у г о л зрения в г р а д у с а х / / коэффициент сжатия о к н а

177

1 ,100.0); g l M a t r i x M o d e (GL_MODELVIEW ) ; glLoadIdentity ( ) ; gluLookAt (
/ / центр с ц е н ы

// расстояние д о плоскостей отсечения

( G L f l o a t ) w/ h ,

/ / положение камеры

0.0 f ,0.0 f ,8.0 f , 0.0 f ,0.0 f ,0.0 f ,

/ / положительное н а п р а в л е н и е о с и y

0.0 f ,1.0 f ,0.0 f ) ;

}

{

void k e y b o a r d ( unsigned char k e y , i n t x , i n t y ) switch ( k e y ) { case 2 7 : /
} exit (0); break ;
* e s c a p e */

/ / Вызывается п р и нажатии клавиши н а к л а в и а т у р е

}
// // //

{

int

Г л а в н ы й ц и к л приложения С о з д а е т с я о к н о , у с т а н а в л и в а е т с я режим э к р а н а с буфером глубины main ( i n t a r g c , char * * a r g v )

g l u t I n i t (& a r g c , a r g v ) ;


178

Приложение Б. Демонстрационные программы
e(

}

glutInitDisplayMod GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH ) ; glutInitWindowSize glutCreateWindow ( init (); glutReshapeFunc ( r glutDisplayFunc ( di glutKeyboardFunc ( glutMainLoop ( ) ; return 0 ;

(500 , 500); argv [ 0 ] ) ; eshape ) ; splay ); keyboard ) ;

Рис. Б.2. Результат работы программы Б.2.

Б.3. Загрузка BMP файла
В этом пункте приводится исходный текст функции

LoadBMP(),

которая позволяет загружать файлы полноцветных изображений (24 бита на точку) в формате Windows Bitmap (BMP). Синтаксис вызова функции:


Б.3. Загрузка BMP файла
i n t LoadBMP ( c o n s t c h a r
Параметр

179

* f i l e n a m e , IMAGE* o u t _ i m g )

lename

определяет имя файла. Результат выполне-

ния функции записывается в структуру делена следующим образом:

out_img,

которая опре-

{

t y p e d e f s t r u c t _IMAGE int width ; int height ; unsigned char
Поля

} IMAGE ;

* data ;

width

и

изображения. В поле

height хранят, соответственно, высоту и ширину data построчно хранится само изображение,

в виде последовательности RGB-компонент цветов пикселей. Программа Б.3. Загрузка BMP. Файл loadbmp.h.

#i f n d e f _LOADBMP_H #d e f i n e _LOADBMP_H t y p e d e f s t r u c t _IMAGE int width ; int height ; unsigned char

{

} IMAGE ;

* data ; * f i l e , IMAGE* o u t _ i m g ) ;

i n t LoadBMP ( c o n s t c h a r #e n d i f

Программа Б.4. Загрузка BMP. Файл loadbmp.cpp.

#i n c l u d e " l o a d b m p . h " #i n c l u d e < s t d i o . h>


180

Приложение Б. Демонстрационные программы

#i n c l u d e < s t d l i b . h> #i n c l u d e #d e f i n e BMP_SIZE_FILEHEADER 1 4 #d e f i n e BMP_SIZE_INFOHEADER 4 0 #d e f i n e BMP_COLOR_BITS_24 2 4
/ / в с п о м о г а т е л ь н ы е функции / / р а з м е р з а г о л о в к а BMP ф а й л а -

/ / р а з м е р и н ф о р м а ц и о н н о г о з а г о л о в к а BMP ф а й л а -

{ } {

s t a t i c unsigned i n t u I n t 1 6 N u m b e r ( unsigned char b u f [ 2 ] ) r e t u r n ( b u f [ 1 ] << 8 ) | b u f [ 0 ] ;

s t a t i c unsigned i n t u I n t 3 2 N u m b e r ( unsigned char b u f [ 4 ] ) u n s i g n e d numb = numb = ( numb << numb = ( numb << numb = ( numb << r e t u r n numb ;
b 8 8 8 u ) ) ) f[ | | | 3] b b b ; uf [ 2 ] ; uf [ 1 ] ; uf [ 0 ] ;

} {

i n t R e a d F i l e H e a d e r ( FILE int o f f s e t = 0 ;
s i z e _ t numb = 0 ;

* f,

int

* bitmap_pos )

u n s i g n e d c h a r h e a d e r [ BMP_SIZE_FILEHEADER ] ; i f ( f s e e k ( f , 0 , SEEK_SET ) ) return 0 ;
numb = f r e a d ( h e a d e r , BMP_SIZE_FILEHEADER, 1 , f ) ;


Б.3. Загрузка BMP файла
i f ( numb ! = 1 ) return 0 ; i f ( h e a d e r [ 0 ] ! = ' B ' | | h e a d e r [ 1 ] ! = 'M ' ) return 0 ;
o f f s e t = uInt32Number ( h e a d e r + 1 0 ) ; numb = f r e a d ( h e a d e r , 4 , 1 , f ) ; i f ( numb ! = 1 ) return 0 ;

181

i f ( uInt3 2Numbe r ( h e a d e r ) != 4 0 ) return 0 ;
* bitmap_pos

}

return 1 ;

= offset ;

/ / з а г р у з к а BMP ф а й л а -

{

i n t LoadBMP ( c o n s t c h a r

* f i l e , IMAGE* o u t _ i m g )

FILE * f ; i n t bitmap_pos ; unsigned char b u f [ 4 0 ] ; s i z e _ t numb ; int x_res ; int y_res ; int n_bits ; int compression ; int size_image ; int n_used_colors ;
/ / открываем файл

f = fopen ( f i l e , " rb " ) ;


182

Приложение Б. Демонстрационные программы

if (! f ) return 0 ; i f ( o u t _ i m g == NULL) return 0 ;
/ / читаем з а г о л о в о к

{ } { }

i f ( ! R e a d F i l e H e a d e r ( f , &b i t m a p _ p o s ) ) return 0 ;
fclose ( f );

i f ( f s e e k ( f , BMP_SIZE_FILEHEADER, SEEK_SET ) ) return 0 ;
fclose ( f );

numb = f r e a d ( b u f , 4 0 , 1 , f ) ; i f ( numb ! = 1 ) { fclose ( f ); return 0 ; } x_res = ( i n t ) uInt32Number ( b u f + 4 ) ; y_res = ( i n t ) uInt32Number ( b u f + 8 ) ; n_bits compression size_image n_used_colors = = = = ( ( ( (

i i i i

n n n n

t t t t

) ) ) )

u u u u

I I I I

n n n n

t t t t

1 3 3 3

6 2 2 2

N N N N

u u u u

m m m m

b b b b

e e e e

r r r r

( ( ( (

b b b b

u u u u

f f f f

+ + + +

1 1 2 3

4 6 0 2

) ) ) )

; ; ; ;

/ / читаем т о л ь к о п о л н о ц в е т н ы е ф а й л ы

i f ( n _ b i t s == BMP_COLOR_BITS_24)


Б.3. Загрузка BMP файла
{

183

int uns int uns int

igned char igned char
rest_4 ; y;

rgb_size ;

* rgb ; * line ;

i f ( bitmap_pos !=
{ } { }

BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER)

return 0 ;

fclose ( f );

i f ( f s e e k ( f , b i t m a p _ p o s , SEEK_SET ) ) return 0 ;
fclose ( f );

r g b _ s i z e = 3 * x_res ; rest_4 = rgb_size % 4 ; i f ( rest_4 > 0) r g b _ s i z e += 4 - r e s t _ 4 ; o u t _ i m g->w i d t h = x _ r e s ; o u t _ i m g-> h e i g h t = y _ r e s ; o u t _ i m g->d a t a = ( unsigned char * ) m a l l o c ( x _ r e s * y _ r e s * 3 ) ;

i f ( o u t _ i m g->d a t a == NULL) return 0 ;
r g b = ( unsigned char * ) m a l l o c ( r g b _ s i z e ) ;
/ / з а п о л н я е м д а н н ы е и з файла


184

Приложение Б. Демонстрационные программы
{

f o r ( y = 0 ; y < y _ r e s ; y++) int x = 0 ;
numb = f r i f ( numb { fclose ( f r e e ( rg } s i z e _ t numb = 0 ; e a d ( rgb , r g b _ s i z e , 1 , f ) ; != 1 )

f ); b ); return 0 ;

}

} fclose ( f ); f r e e ( rgb ) ;

numb = 0 ; l i n e = o u t _ i m g->d a t a + x _ r e s * 3 * y ; f o r ( x = 0 ; x < x _ r e s ; x++) { l i n e [ 2 ] = r g b [ numb + + ] ; l i n e [ 1 ] = r g b [ numb + + ] ; l i n e [ 0 ] = r g b [ numb + + ] ; l i n e += 3 ; }

else return 0 ;

}

return 1 ;

t y p e d e f u n s i g n e d c h a r BYTE ; t y p e d e f u n s i g n e d s h o r t WORD; t y p e d e f u n s i g n e d i n t DWORD; t y p e d e f s t r u c t tagBITMAPFILEHEADER


Б.3. Загрузка BMP файла
{ WORD bfType ; DWORD bfSize ; WORD bfReserved1 ; WORD bfReserved2 ; DWORD bfOffBits ; } BITMAPFILEHEADER ; biSize ; biWidth ; biHeight ; WORD b i P l a n e s ; WORD b i B i t C o u n t ; DWORD b i C o m p r e s s i o n ; DWORD b i S i z e I m a g e ; long biXPelsPerMeter ; long biYPelsPerMeter ; DWORD b i C l r U s e d ; DWORD b i C l r I m p o r t a n t ; } BITMAPINFOHEADER ;

185

t y p e d e f s t r u c t tagBITMAPINFOHEADER {
DWORD

long long

{ } {

s t a t i c v o i d I n t T o 2 B y t e s ( i n t v a l , BYTE b u f [ 2 ] )
b u f [ 0 ] = (BYTE) v a l ; b u f [ 1 ] = (BYTE ) ( v a l >> 8 ) ;

s t a t i c v o i d I n t T o 4 B y t e s ( i n t v a l , BYTE b u f [ 4 ] )
b b b b u u u u f f f f [ [ [ [ 0 1 2 3 ] ] ] ] = = = = ( ( ( ( BYTE BYTE BYTE BYTE ) ) ) ) v ( ( ( a v v v l a a a ; l >> 8 ) ; l >> 1 6 ) ; l >> 2 4 ) ;

}


186

Приложение Б. Демонстрационные программы

Б.4. Пример 3: Текстурирование и анимация
Результатом выполнения этой программы является построение тетраэдра с вращающимися вокруг него кольцами, на которые нанесена текстура. При компиляции программы в Microsoft Visual C++ файл ?texture.bmp? надо поместить в каталог проекта или указать полный путь к нему. Если путь не указан, то при запуске исполняемого файла из операционной системы файл с текстурой должен находиться в том же каталоге. Для загрузки изображения текстуры программа использует функцию денную в предыдущем пункте. Программа Б.5. Пример текстурирования и анимации.

LoadBMP,

приве-

#i #i #i #i

n n n n

c c c c

l l l l

u u u u

d d d d

e e e e

< s t d l i b . h> " loadbmp . h "

#d e f i n e TETR_LIST 1
GLfloat l i g h t _ c o l [ ] = { 1 , f l o a t mat_diff1 [ ] = { 0 . 8 , 0 . f l o a t mat_diff2 [ ] = { 0 . 0 , 0 . f l o a t mat_amb [ ] = { 0 . 2 , 0 . 2 f l o a t mat_spec [ ] = { 0 . 6 , 0 . 6 f l o a t s h i n i n e s s =0.7 * 1 2 8 RingHeight =0.1; GLUquadricObj * QuadrObj ; GLuint TexId ; GLfloat TetrVertex [ 4 ] [ 3 ] , 1 8 0 , , , ,1}; ,0.8}; ,0.9}; 0.2}; 0.6}; CurAng = 0 , R i n g R a d = 1 ,

TetrNormal [ 4 ] [ 3 ] ;

void g e t n o r m ( f l o a t a [ 3 ] , f l o a t b [ 3 ] , f l o a t c [ 3 ] , f l o a t *n )

/ / Вычисление нормали к п л о с к о с т и , / / з а д а в а е м о й точками a , b , c


Б.4. Пример 3: Текстурирование и анимация
{

187

n[0 ( n[1 ( n[2 (

f l o a t mult =0; int i , j ;
] = ( b[1] c [1] - a ] = ( c [0] c [2] - a ] = ( b[0] b[1] - a
-a [1] -a [2] -a [1]

}
//

/ / О п р е д е л е н и е нужного н а п р а в л е н и я н о р м а л и : / / от точки ( 0 , 0 , 0 ) f o r ( i = 0 ; i < 3 ; i ++) m u l t+=a [ i ] * n [ i ] ; i f ( m u l t <0) f o r ( j = 0 ; j < 3 ; j ++) n [ j ]=-n [ j ] ; В ы ч и с л е н и е к о о р д и н а т вершин т е т р а э д р а

[ ) [ ) [ )

1 ] ) * ( c [2] - a [ 2 ] ) - ( b[2] - a [ 2 ] ) * ; 0 ] ) * ( b[2] - a [ 2 ] ) - ( b[0] - a [ 0 ] ) * ; 0 ] ) * ( c [1] - a [ 1 ] ) - ( c [0] - a [ 0 ] ) * ;

{

void I n i t V e r t e x T e t r ( ) f l o a t a l p h a =0; int i ;

/ / Вычисление к о о р д и н а т о с н о в а н и я тетраэдра

TetrVertex [ 0 ] [ 0 ] = 0 ; TetrVertex [ 0 ] [ 1 ] = 1 . 3 ; TetrVertex [ 0 ] [ 2 ] = 0 ;

{

f o r ( i = 1 ; i < 4 ; i ++)
Tetr Tetr Tetr alph Vert Vert Vert a += ex ex ex 12 [ [ [ 0 i i i . ] ] ] 0

}

}

[ 0 ] = 0 . 9 4 * cos ( alpha ) ; [1]=0; [ 2 ] = 0 . 9 4 * s i n ( alpha ) ; *3.14/180.0;

{

void I n i t N o r m s T e t r ( )

/ / Вычисление н о р м а л е й сторон тетраэдра

getnorm ( T e t r V e r t e x [ 0 ] , T e t r V e r t e x [ 1 ] ,


188

Приложение Б. Демонстрационные программы
e e e e e e e t t t t t t t r r r r r r r V V V V V V V e e e e e e e r r r r r r r t t t t t t t e e e e e e e x x x x x x x [ [ [ [ [ [ [ 2 0 3 0 1 1 3 ] ] ] ] ] ] ] , , , , , , , T T T T T T T e e e e e e e trNormal trVertex trNormal trVertex trNormal trVertex trNormal [ [ [ [ [ [ [ 0 2 1 3 2 2 3 ] ] ] ] ] ] ] ) , ) , ) , ) ; ; ; ;

}

T getnorm ( T T getnorm ( T T getnorm ( T T

{

void M a k e T e t r L i s t ( ) int i ;

/ / С о з д а н и е с п и с к а п о с т р о е н и я тетраэдра

/ / З а д а н и е сторон тетраэдра

g l N e w L i s t ( TETR_LIST , GL_COMPILE ) ; g l B e g i n (GL_TRIANGLES ) ; glNormal3fv glVertex3fv glVertex3fv i f ( i !=3) glVertex3

{

f o r ( i = 1 ; i < 4 ; i ++)

( TetrNormal [ i - 1 ] ) ; ( TetrVertex [ 0 ] ) ; ( TetrVertex [ i ] ) ; fv ( TetrVertex [ i +1 ] );

else

} {

} g g g g g g

glVertex3fv ( TetrVertex [ 1 ] ) ; 3 3 3 3 f f f f v v v v ( ( ( ( T T T T e e e e trNormal trVertex trVertex trVertex [ [ [ [ 3 1 2 3 ] ] ] ] ) ) ) ) ; ; ; ;

lNormal lVertex lVertex lVertex lEnd ( ) ; lEndLis

t ();

v o i d DrawRing ( )
// Построение цил ин др а ( к о л ь ц а ) , р а с п о л о ж е н н о г о


Б.4. Пример 3: Текстурирование и анимация
/ / / / / / / / / / / / паралле Второй радиусы последн вдоль о цилиндр льно оси z и третий п оснований и е д в а -ч и с с и z . При а находитс араметры задают , четвертый в ы с о т у , ло разбиений в о к р у г и этом д а л ь н е е о с н о в а н и е я в п л о с к о с т и z =0

189

} {

g l u C y l i n d e r ( QuadrObj , RingRad , RingRad , RingHeight , 3 0 , 2 ) ;

void T e x t u r e I n i t ( ) c h a r s t r F i l e [ ] = " t e x t u r e . bmp" ; IMAGE i m g ;
/ / В ы р а в н и в а н и е в * . bmp п о б а й т у

/ / С о з д а н и е и д е н т и ф и к а т о р а д л я текстуры / / З а г р у з к а и з о б р а ж е н и я в память

g l P i x e l S t o r e i (GL_UNPACK_ALIGNMENT, 1 ) ;

g l G e n T e x t u r e s (1 ,& TexId ) ;

i f ( ! LoadBMP ( s t r F i l e , &i m g ) ) return ; ;

/ / Н а ч а л о о п и с а н и я с в о й с т в текстуры

// С о з д а н и е у р о в н е й детализации и инициализация / / текстуры

g l B i n d T e x t u r e (GL_TEXTURE_2D, T e x I d ) ;

g l u B u i l d 2 D M i p m a p s (GL_TEXTURE_2D, 3 , img . w i d t h , img . h e i g h t , GL_RGB, GL_UNSIGNED_BYTE, i m g . d a t a ) ;

/ / Р а з р е ш е н и е н а л о ж е н и я э т о й текстуры н а / / q u a d r i c -о б ъ е к т ы

g l u Q u a d r i c T e x t u r e ( Q u a d r O b j , GL_TRUE ) ;

/ / З а д а н и е п а р а м е т р о в текстуры / / Повтор и з о б р а ж е н и я п о п а р а м е т р и ч е с к и м


190

Приложение Б. Демонстрационные программы

/ / осям s и t

g l T e x P a r a m e t e r i (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ) ; g l T e x P a r a m e t e r i (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) ;

/ / Не и с п о л ь з о в а т ь интерполяцию п р и в ы б о р е точки / / н а текстуре

g l T e x P a r a m e t e r i (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ; g l T e x P a r a m e t e r i (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) ;

/ / Совмещать текстуру и материал о б ъ е к т а

}

g l T e x E n v i (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;

{

void I n i t ( void )
InitVertexTetr ( ) ; InitNormsTetr ( ) ; MakeTetrList ( ) ;
/ / О п р е д е л е н и е с в о й с т в материала

g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_AMBIENT, mat_amb ) ; g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec ) ; g l M a t e r i a l f (GL_FRONT, GL_SHININESS , shininess );

// Определение свойств освещения

g l L i g h t f v ( GL_LIGHT0 , GL_DIFFUSE , l i g h t _ c o l ) ; g l E n a b l e ( GL_LIGHTING ) ; g l E n a b l e ( GL_LIGHT0 ) ;


Б.4. Пример 3: Текстурирование и анимация
/ / Проводить у д а л е н и е невидимых линий и // поверхностей / / Проводить н о р м и р о в а н и е н о р м а л е й / / Материалы о б ъ е к т о в отличаются т о л ь к о цветом / / д и ф ф у з н о г о отражения

191

g l E n a b l e (GL_DEPTH_TEST ) ; g l E n a b l e (GL_NORMALIZE ) ;

g l E n a b l e (GL_COLOR_MATERIAL ) ; g l C o l o r M a t e r i a l (GL_FRONT_AND_BACK, GL_DIFFUSE ) ;

Q u a d r O b j=g l u N e w Q u a d r i c ( ) ; TextureInit ( ) ;

/ / С о з д а н и я у к а з а т е л я н а q u a d r i c -о б ъ е к т // для построения к о л е ц / / О п р е д е л е н и е с в о й с т в текстуры // Задание перспективной проекции

/ / Д а л е е будет п р о в о д и т ь с я только // п р е о б р а з о в а н и е о б ъ е к т о в сцены

g l M a t r i x M o d e (GL_PROJECTION ) ; gluPerspective (89.0 , 1.0 , 0.5 , 100.0);

} {

g l M a t r i x M o d e (GL_MODELVIEW ) ;

void D r a w F i g u r e s ( void )
/ / В к л ю ч е н и е режима н а н е с е н и я текстуры / / З а д а е м цвет д и ф ф у з н о г о отражения д л я к о л е ц / / Чтобы н е п р о в о д и т ь п е р е м н о ж е н и е с п р е д ы д у щ е й / / матрицей загружаем е д и н и ч н у ю матрицу / / О п р е д е л я е м точку н а б л ю д е н и я

g l E n a b l e (GL_TEXTURE_2D ) ; g l C o l o r 3 f v ( mat_diff1 ) ;

glLoadIdentity ( ) ;


192

Приложение Б. Демонстрационные программы

/ / С о х р а н я е м в и д о в у ю матрицу , так к а к д а л ь ш е // будет п р о в о д и т ь с я поворот к о л е ц / / / /

gluLookAt ( 0 . 0 , 0 . 0 , 2 . 5 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0); glPushMatrix ( ) ;
/ / / /

glPushMatrix glTranslatef DrawRing ( ) ; glPopMatrix ( glPushMatrix glTranslatef glRotatef (9 DrawRing ( ) ; glPopMatrix ( glPushMatrix glTranslatef glRotatef (9 DrawRing ( ) ;

/ / Для р и с о в а н и я к о л е ц каждое и з н и х н а д о / / п р е о б р а з о в а т ь о т д е л ь н о , поэтому с н а ч а л а / / с о х р а н я е м в и д о в у ю матрицу , затем в о с с т а н а в л и в а е м

g l R o t a t e f ( CurAng , 1 , 0 , 0 ) ;

Производим н е с к о л ь к о п о в о р о т о в на новый у г о л ( это б ы с т р е е , чем умножать предыдущую в и д о в у ю матрицу н а матрицу п о в о р о т а с ф и к с и р о в а н н ы м углом поворота ) g l R o t a t e f (- CurAng , 1 , 1 , 0 ) ;

(); (0 ,0 , - RingHeight / 2 ) ;

); (); ( 0 , RingHeight / 2 , 0 ) ; 0 ,1 ,0 ,0); ); (); (- R i n g H e i g h t / 2 , 0 , 0 ) ; 0 ,0 ,1 ,0);

/ / В о с с т а н а в л и в а е м матрицу д л я п о в о р о т о в т е р а э д р а / / Выключаем режим наложения текстуры

glPopMatrix ( ) ; glPopMatrix ( ) ;

g l D i s a b l e (GL_TEXTURE_2D ) ;

/ / Проводим повороты

g l R o t a t e f ( CurAng , 1 , 0 , 0 ) ;


Б.4. Пример 3: Текстурирование и анимация
g l R o t a t e f ( CurAng / 2 , 1 , 0 , 1 ) ;
/ / Чтобы т е т р а э д р в р а щ а л с я в о к р у г центра , е г о // н а д о сдвинуть в н и з по о с и o z g l T r a n s l a t e f ( 0 , -0.33 , 0 ) ;

193

/ / З а д а е м цвет д и ф ф у з н о г о отражения д л я т е т р а э д р а

g l C o l o r 3 f v ( mat_diff2 ) ; g l C a l l L i s t ( TETR_LIST ) ;

/ / Проводим п о с т р о е н и е тетраэдра

} {

void D i s p l a y ( void )
/ / Инициализация ( очистка ) текущего б у ф е р а // к а д р а и глубины // Построение о б ъ е к т о в

g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;

// Перестановка б у ф е р о в к а д р а

DrawFigures ( ) ;

} {

glutSwapBuffers ( ) ;

v o i d Redraw ( v o i d )
C u r A n g +=1;
/ / У в е л и ч е н и е текущего у г л а п о в о р о т а / / Сигнал д л я в ы з о в а п р о ц е д у р ы с о з д а н и я изображения // ( для о б н о в л е н и я )

} {

glutPostRedisplay ( ) ;

i n t main ( i n t a r g c , char

** a r g v )


194

Приложение Б. Демонстрационные программы

/ / И н и ц и а л и з а ц и я ф ун кц ий б и б л и о т е к и GLUT / / З а д а н и е режима с д в о й н о й б у ф е р и з а ц и е й , / / п р е д с т а в л е н и е ц в е т а в формате RGB, // и с п о л ь з о в а н и е буфера глубины

g l u t I n i t (& a r g c , a r g v ) ;

/ / С о з д а н и е о к н а приложения

g l u t I n i t D i s p l a y M o d e (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ) ;

/ / Р е г и с т р а ц и я функции п о с т р о е н и я и з об р а же н и я / / Р е г и с т р а ц и я функции о б н о в л е н и я и зо б ра ж е ни я / / И н и ц и а л и з а ц и я ф ун кц ий OpenGL / / Цикл о б р а б о т к и с о б ы т и й

g l u t C r e a t e W i n d o w ( " E x a m p l e o f u s i n g OpenGL" ) ; glutDisplayFunc ( Display ) ; g l u t I d l e F u n c ( Redraw ) ; Init ();

}

return 0 ;

glutMainLoop ( ) ;

Рис. Б.3. Результат работы программы Б.5.


Б.5. Класс для работы с OPENGL в WIN32

195

Б.5. Класс для работы с OpenGL в Win32
Программа Б.6. Файл glrc.h.

#i f n d e f _GLRC_H_ #d e f i n e _GLRC_H_ #i n c l u d e < g l / g l . h> #i n c l u d e < g l / g l u . h>
{
/ / з а г о л о в к и OpenGL

c l a s s GLRC

public :
GLRC( HWND wnd ) ; ~GLRC ( ) ;
/ / деструктор / / у д а л е н и е ( также в ы з ы в а е т с я и з д е с т р у к т о р а ) / / С о з д а н и е контекста р и с о в а н и я . / / Н е о б х о д и м о в ы з в а т ь д о и с п о л ь з о в а н и я OpenGL / / С о з д а н л и контекст р и с о в а н и я ? / / с о з д а н и е и з идентификатора о к н а

void D e s t r o y ( ) ; bool C r e a t e ( ) ;

bool I s C r e a t e d ( ) ;

bool I s C u r r e n t ( ) const ; bool MakeCurrent ( ) ;

/ / Является л и контекст р и с о в а н и я текущим?

/ / Делает контект текущим


196

Приложение Б. Демонстрационные программы

void S w a p B u f f e r s ( ) ; private : bool m_created ;
HWND m_wnd ; HDC m_dc ;

/ / Вызывается в к о н ц е р и с о в а н и я , / / п о к а з с о з д а н н о г о изображения

/ / с о з д а н л и контекст / / о к н о , д л я к о т о р о г о контекст / / контекст у с т р о й с т в а / / контекст р и с о в а н и я OpenGL

HGLRC m _ g l r c ; };

#e n d i f
Программа Б.7. Файл glrc.cpp.

#i n c l u d e #i n c l u d e " g l r c . h " #i n c l u d e " a s s e r t . h "
GLRC : : GLRC(HWND wnd ) : m_created ( f a l s e ) { a s s e r t ( wnd ) ; m_wnd = wnd ; m_dc = : : GetDC ( wnd ) ; a s s e r t ( m_dc ) ; } GLRC : : ~ GLRC ( ) { i f ( m_created )


Б.5. Класс для работы с OPENGL в WIN32
} { Destroy ( ) ;

197

v o i d GLRC : : D e s t r o y ( )
w g l D e l e t e C o n t e x t ( m_glrc ) ; : : R e l e a s e D C ( m_wnd, m_dc ) ; m_created = f a l s e ;

} {

b o o l GLRC : : M a k e C u r r e n t ( )
a s s e r t ( m_created ) ;

i f ( IsCurrent ( ) ) return true ;
BOOL r e s = w g l M a k e C u r r e n t ( m_dc , m _ g l r c ) ; r e t u r n ( r e s ! = FALSE ) ;

} {

b o o l GLRC : : C r e a t e ( )
a s s e r t ( ! m_created ) ;

int nPixelFormat = 0 ;
DWORD f l a g s ; flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ; {

s t a t i c PIXELFORMATDESCRIPTOR p f d =
1,

s i z e o f (PIXELFORMATDESCRIPTOR ) ,


198

Приложение Б. Демонстрационные программы
flags , PFD_TYPE_RGBA, 24 , 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32 , 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0

};

pfd . cAlphaBits = 8 ; n P i x e l F o r m a t = C h o o s e P i x e l F o r m a t ( m_dc , &p f d ) ; BOOL r e s = S e t P i x e l F o r m a t ( m_dc , n P i x e l F o r m a t , &p f d ) ;

i f ( r e s == FALSE ) return f a l s e ;
m _ g l r c = w g l C r e a t e C o n t e x t ( m_dc ) ; m_created = true ; } {

return MakeCurrent ( ) ;

v o i d GLRC : : S w a p B u f f e r s ( )
a s s e r t ( m_created ) ; : : S w a p B u f f e r s ( m_dc ) ;


Б.5. Класс для работы с OPENGL в WIN32
} { } { }

199

b o o l GLRC : : I s C u r r e n t ( ) c o n s t r e t u r n : : w g l G e t C u r r e n t C o n t e x t ( ) == m _ g l r c ;
a s s e r t ( m_created ) ;

b o o l GLRC : : I s C r e a t e d ( ) return m_created ;



Приложение В.

Примеры практических заданий

В.1. Cornell Box
Целью задания является создание изображения заданной трехмерной статичной сцены средствами Op enGL с использованием стандартных геометрических примитивов. Требуется создать изображение сцены Cornell Box. Эта классическая сцена представляет собой комнату кубического вида, с отсутствующей передней стенкой. В комнате находятся геометрические предметы различных форм и свойств (кубы, параллелепипеды, шары), а также протяженный источник света на потолке. Присутствует также камера с заданными параметрами (обычно она расположена так, чтобы была видна вся комната). В одной из лабораторий Корнельского университета такая комната существует в реальности, и ее фотографии сравниваются с изображениями, построенными методами трассировки лучей для оценки точности методов. На странице лаборатории (http://graphics.cornell.edu) можно найти описание геометрии сцены в текстовом формате. 201


202

Приложение В. Примеры практических заданий

Рис. В.1. Пример сцены Cornell Box.

Реализации сцены, приведенной на рисунке В.1, достаточно для выполнения задания, хотя возможно введение новых предметов дополнительно к существующим или вместо них. Приветствуется использование примитивов библиотек GLUT и GLU. Внимание! Сцена не должна превращаться в набор разнородных предметов. Эстетичность и оригинальность выполненного задания принимается во внимание. Протяженный источник света на потолке комнаты можно эмулировать несколькими точечными источниками. За простейшую реализацию сцены ставится 7 баллов. Реалистичность сцены можно значительно повысить за счет разбиения многоугольников. Суть этого в том, что в модели освещения Op enGL освещенность вычисляется в вершинах многоугольника с учетом направления нормалей в этих вершинах, а затем линейно интерполируется по всей поверхности. Если используются относительно большие многоугольники, то, очевидно, невозможно получить действительно плавные переходы и за-


В.1. CORNELL BOX

203

тенения. Для преодоления этого недостатка можно разбивать большие грани (стены, например) на множество меньших по размерам. Соответственно разброс в направлении нормалей в вершинах одного многоугольника не будет столь велик и затенение станет более плавным (1 балл). Наложение текстур на объекты сцены поощряется 2-мя баллами. Дополнительными баллами оценивается присутствие в сцене теней. Один из простейших алгоритмов наложения теней приведен в разделе 8.2. За его реализацию можно получить до 2 баллов. Использование более продвинутых алгоритмов (например, shadow volumes) будет оценено дополнительными баллами. Реализация устранения ступенчатости (antialiasing) методом, предложенным в разделе 8.1 или каким-либо другим, оценивается в 2 балла. За введение в сцену прозрачных объектов и корректный их вывод дается 1 балл. Механизм работы с прозрачными объектами описан в разделе 7.1. Задание оценивается, исходя из 15 баллов. В приведенной ниже таблице указано распределение баллов в зависимости от реализованных требований: Простейший вариант сцены (только освещение) Разбиение полигонов Использование текстур Наложение теней Устранение ступенчатости Использование прозрачных объектов 7 баллов +1 балл +2 балла +2 балла +2 балла +1 балл

Дополнительные баллы можно получить за хорошую оптимизацию программы, необычные решения, эстетичность и т.д.


204

Приложение В. Примеры практических заданий

В.2. Виртуальные часы
Целью задания является создание трехмерной интерактивной модели аналоговых часов.

Рис. В.2. Пример трехмерных виртуальных часов. Обязательные требования к программе:



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



Часы на экране обязательно должны иметь минутную и часовую стрелки. Секундная по желанию, но очень приветствуется (иначе трудно будет определить, ходят часы или нет).


В.2. Виртуальные часы

205



Время на часах должно совпадать с системным временем компьютера. Часы обязательно должны ходить, т.е. стрелки должны двигаться, и скорость их движения не должна зависеть от производительности компьютера, а определяться только текущим временем. Сцена должна быть интерактивной, т.е. давать приемлемую частоту кадров в секунду (>10) при визуализации на машине с аппаратным ускорителем трехмерной графики. Если программа будет работать медленно, баллы могут быть снижены. Необходимо реализовать вращения часов (или, возможно, камеры) с помощью мыши (предпочтительно) или клавиатуры. Можно также предусмотреть режимы с автоматическим вращением.

Пожелания к программе:



Поощряется введение дополнительной геометрии. Например, ремешков, маятников и т.д. Можно сделать часы с кукушкой, будильник и т.п. Желательно наличие возможностей для управления процессом визуализации. Например, наличие/отсутствие текстур, режимы заливки, детализации и т.д. Приветствуется выполнение задания в виде демонстрации, т.е. c возможностью работы в полноэкранном режиме и немедленным выходом по клавише Escap e. Можно написать программу как Screen Saver. Постарайтесь использовать максимум возможностей библиотеки Op enGL. Блики, отражения, спецэффекты за все это обязательно даются дополнительные баллы.


206

Приложение В. Примеры практических заданий



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

Максимальная оценка 20 баллов. За минимальную реализацию требований ставиться 10 баллов. Еще до 10 баллов можно получить за использование в работе возможностей Op enGL (текстур, прозрачности, сферического текстурированяи и пр.), оригинальных и продвинутых алгоритмов, количество настроек, а также за эстетичность и красоту сцены.

В.3. Интерактивный ландшафт
Целью данного задания является генерация и вывод с помощью Op enGL поверхности ландшафта, а также обеспечение интерактивного передвижения над ней.

Рис. В.3. Пример трехмерного ландшафта.


В.3. Интерактивный ландшафт
Обязательная часть задания

207

Для выполнения обязательной части задания необходимы:



генерация трехмерного ландшафта раскраска для придания реалистичности эффект тумана возможность ?полета? над ландшафтом (управление)

Более подробное описание:

Генерация ландшафта

Один из вариантов задания поверхности ландшафта задание так называемого ?поля высот? функции вида которая сопоставляет каждой точке

(x, y )

плоскости

z = f (x, y ), OX Y число

z

высоту поверхности ландшафта в этой точке. Один из спосо-

f представx и y f = T [x, y ], а для дробных x и y из диапазонов [0..M - 1] и [0..N - 1] соответственно, f вычисляется интерполяцией значений f в ближайших точках плоскости O X Y с целыми x и y , а вне указанных диапазонов x и y значение функции считается неопределенным.
бов задания функции ляется матрицей табличный, когда функция

f

T

размера

M ЧN

, и для целых

Допустим, в памяти лежит двухмерный массив со значениями матрицы

T . Пусть N = M . Если теперь для каждого квадрата [x, x + 1] Ч [y , y + 1], где x и y принадлежат диапазону [0..N - 2] построить две грани: ((x, y , T [x, y ]), (x + 1, y , T [x + 1, y ]), (x + 1, y + 1, T [x + 1, y + 1])) и ((x, y , T [x, y ]), (x + 1, y + 1, T [x + 1, y + 1]), (x, y + 1, T [x, y + 1])), то мы получим трехмерную модель поверхности,
описываемой матрицей Т. Но каким образом задать массив значений матрицы

T

? Один

из способов сгенерировать псевдослучайную поверхность с по-


208

Приложение В. Примеры практических заданий
T
равной

мощью фрактального разбиения. Для этого положим размерность матрицы

2

N

+1

, где

N

натуральное число.

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

T

, соответствующего середине ребра. Для этого

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

цы. Значения их угловых элементов уже определены, и мы можем рекурсивно применить к подматрицам пока все элементы процедуру. Будем спускаться рекурсивно по дереву подматриц не будут определены. С помощью подбора коэффициентов генерации псевдослучайной добавки можно регулировать ?изрезанность? поверхности. Для реалистичности поверхности важно сделать величину псевдослучайной добавки зависящей от длины текущего ребра с уменьшением размера ребра должно уменьшаться и возможное отклонение высоты его середины от среднего арифметического высот его вершин. Один из других вариантов использовать изображения в градациях серого для карты высот. (В этом случае ландшафт можно оттекстурировать с помощью соответствующей цветной картинки и линейной генерации текстурных координат). Внимание: использование NURBS возможно, но не приветствуется в силу ограниченности использования NURBS для реальных приложений.


В.3. Интерактивный ландшафт
Раскраска ландшафта

209

Чтобы сделать получившуюся модель немного более напоминающей ландшафт, ее можно раскрасить. Каждой вершине можно сопоставить свой цвет, зависящий от высоты этой вершины. Например, вершины выше определенного уровня можно покрасить в белый цвет в попытке сымитировать шапки гор, вершины пониже в коричневый цвет скал, а вершины уровнем еще ниже в зеленый цвет травы. Значения ?уровней? раскраски поверхности следует подобрать из эстетических соображений.

Освещение ландшафта

Для еще большего реализма и для подчеркивания рельефа осветить модель ландшафта бесконечно удаленным источником света (как бы солнцем). Цвет вершин можно задавать через

glColor

совместно с

g l C o l o r M a t e r i a l (GL_FRONT, GL_AMBIENT_AND_DIFFUSE ) ;
Туман

Чтобы усилить (или хотя бы создать) иллюзию больших размеров модели и ее протяженности, можно воспользоваться эффектом тумана. Тип тумана (линейный или экспоненциальный) следует выбрать из индивидуальных эстетических предпочтений. Способ создания тумана описан в разделе 5.4.

Управление

Элементарное управление движением камеры по клавиатурным ?стрелочкам?. Нажатие на стрелку ?вверх? передвижение по направлению взгляда вперед. ?Назад? по направлению взгляда назад. ?Влево?, ?Вправо? по аналогии, ?Page Up?, ?Page Down? вверх, вниз, соответственно.


210

Приложение В. Примеры практических заданий
В GLUT'е получать клавиш нажатия можно не через алфавитфункцию

но-цифровых

glutSpecialFunc(void (*)(int key, int x , int y)), где key константа, обозначающая клавишу (см. в glut . h GLUT_KEY). Функция используется аналогично glutKeyb oardFunc().
Дополнительная часть
Управление мышью

Движение мыши в горизонтальной плоскости (смещение по оси

X

) управляет углом поворота направления взгляда в гори-

зонтальной плоскости (угол альфа вертикальной плоскости

[0..2 ]). (смещение по оси Y [- .. ]).

Движение мыши в ) управляет углом

поворота направления взгляда в вертикальной плоскости относительно горизонта (угол бета дующим образом: Зная оба угла, вектор направления взгляда в мировых координатах вычисляется сле-

d i r e c t i o n _ z = s i n ( бета ) ; d i r e c t i o n _ x = c o s ( альфа ) * c o s ( б е т а ) ; d i r e c t i o n _ y = s i n ( альфа ) * c o s ( б е т а ) ;
а затем нормализуется. Вектор направления ?вбок? вычисляется как векторное произведение вектора направления вертикально вверх, то есть вектора

(0, 0, 1)

и уже известного вектора направления взгляда.

Вектор направления ?вверх? вычисляется как векторное произведение вектора направления взгляда и вектора направления ?вбок?. Положение камеры в Op enGL можно передать c помощью команды равным

gluLookAt(). Подсказка: position + direction.

параметр

target

можно положить

Смещение позиции камеры должно происходить не на фиксированное расстояние за один кадр, а вычисляться, исходя из


В.3. Интерактивный ландшафт

211

скорости передвижения камеры, и времени, ушедшего на обсчет последнего кадра. Передвижение камеры должно осуществляться в направлении взгляда. Скажем, по левой кнопке мыши вперед, а по правой назад. Для того, чтобы засечь время, можно воспользоваться функцией ко для Windows).

timeGetTime()

, описанной в

?mmsystem.h?, и реализованной в библиотеке ?winmm.lib? (толь-

#i n c l u d e " mmsystem . h "
{ ...

void D i s p l a y ( )
e_rendering ; n d e r i n g = timeGetTime ( ) ; ng_msec = -s y s t e m _ t i m e _ b e f o r e _ r e n d e r i n g ;

...

int system_time_befor system_time_before_re RenderFrame ( ) ; int time_spent_renderi timeGetTime ( ) ... }
):

timeGetTime()

В GLUT'е для этого есть специальный вызов (аналогично

t i m e = g l u t G e t (GLUT_ELAPSED_TIME ) ;
Вода, или нечто на нее похожее

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


212

Приложение В. Примеры практических заданий

цы генерируется значение высоты ниже этого порога, элемент инициализируется пороговым значением.

Объекты

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

Отражения в воде

Сделать так, чтобы ландшафт отражался в воде, которая уже должна присутствовать на ландшафте (то есть подразумевается, что это дополнительное задание является развитием дополнительного задания 2). Один из вариантов реализации: рассчитав текущую матрицу камеры, отразить ее относительно плоскости воды и изображения ландшафта, не выводя при этом грани поверхности воды. Затем, пользуясь еще не отраженной матрицей камеры, визуализировать грани поверхности воды полупрозрачными. Это создаст иллюзию поверхности воды, сквозь которую видно отражение. Затем, опять же с неотраженной матрицей камеры, нужно нарисовать сам ландшафт (этот подход является частным случаем описанного в разделе 8.3).

Тени

На этапе раскраски вершин ландшафта (то есть это надо сделать один раз, а не каждый кадр) из каждой вершины можно выпустить луч, противоположный направлению солнца. Если луч не пересекся с поверхностью ландшафта раскрашивать как


В.3. Интерактивный ландшафт

213

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

Оценка
Ландшафт Раскраска Управление Управление мышью Объекты Вода Отражение Тени 8 баллов +2 балла +2 балла +2 балла +3 балла +4 балла +4 балла +5 баллов

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

Дополнительные источники информации



http://www.vterrain.org



Литература
[1] Каннингем, С. ACM SIGGRAPH и обучение машинной графике в Соединенных Штатах. Программирование, 4, 1991. [2] Bayakovsky, Yu. Russia: Computer Graphics Education Takes o in 1990s. Computer Graphics, 30(3), Aug. 1996. [3] Canningham S. An Evoluing Approach to CG Courses in CS. Graphicon'98 Conference Pro ceedings, MSU, Sept. 1998. [4] Bayakovsky, Yu. Virtual Lab oratory for Computer Graphics and Machine Vision. Graphicon'99, Conference pro ceedings, MSU, Sept 1999. [5] Эйнджел Э. Интерактивная компьютерная графика. Вводный курс на базе Op enGL, 2 изд. Пер. с англ.- Москва, ?Вильямс?, 2001. [6] Порев В.Н. Компьютерная графика. СПб., BHV, 2002. [7] Шикин А. В., Боресков А. В. Компьютерная графика. Полигональные модели. Москва, ДИАЛОГ-МИФИ, 2001. [8] Тихомиров Ю. Программирование трехмерной графики. СПб, BHV, 1998. [9] Performance Op enGL: Platform Indep endent Techniques.

SIGGRAPH 2001 course. 215


216

Литература

[10] Op enGL p erformance optimization, Siggraph'97 course. [11] Visual Intro duction in Op enGL, SIGGRAPH'98. [12] The Op enGL graphics system: a sp ecication (version 1.1). [13] Программирование GLUT: окна и анимация. Miguel Angel Sepulveda, LinuxFo cus. [14] The Op enGL Utility To olkit (GLUT) Programming Interface, API version 3, sp ecication. [15] А. Игнатенко. Однородные координаты. ?Графика Научнои Муль-

образовательный

интернет-журнал

тимедиа?. http://cgm.graphicon.ru/content/view/51/61/.


Предметный указатель
API, 11 GLU, Graphics Utility Library, 26 GLUT, GL Utility To olkit, 27 IRIS GL, 12 Op enGL, 11 cинтаксис команд, 30 оптимизация, 115 особенности, 12 ошибки, 127 приемы работы, 101 Tao Framework, 157 Анимация, 20 Буфер глубины, 62, 90 маски, 94 накопитель, 93 очистка, 40 Граничные модели, 19 217 Графический процесс, 18 Команды GL glAccum, 94 glArrayElement, 50 glBegin, 44 glBindTexture, 80 glBlendFunc, 91 glCallList, 48 glCallLists, 48 glClear, 40 glClearColor, 40 glColor, 42 glColorMaterial, 68 glColorPointer, 50 glCullFace, 46 glDeleteLists, 48 glDepthRange, 64 glDisable, 43 glDisableClientState, 50 glDrawArrays, 50 glDrawBuer, 93 glDrawElements, 51 glEnable, 43


218

Предметный указатель
glEnableClientState, 50 glEnd, 44 glEndList, 47 glFog, 73 glFrontFace, 45 glGenTextures, 80 glHint, 96 glLight, 69 glLightMo del, 66 glLoadIdentity, 57 glLoadMatrix, 57 glMaterial, 67 glMatrixMo de, 56 glMultMatrix, 57 glNewList, 47 glNormal, 43 glNormalPointer, 50 glOrtho, 60 glPopMatrix, 57 glPushMatrix, 57 glReadBuer, 93 glRotate, 59 glScale, 59 glShadeMo del, 42 glStencilFunc, 95 glStencilOp, 95 glTexCo ord, 85 glTexEnv, 83 glTexGen, 85 glTexParameter, 81 glTranslate, 59 glVertex, 31, 41 glVertexPointer, 49 glViewp ort, 63 Команды GLU gluBuild2DMipmaps, 79 gluCylinder, 47, 165 gluDisk, 166 gluLo okAt, 60 gluNewQuadric, 47 gluOrtho2D, 60 gluPartialDisk, 166 gluPersp ective, 61 gluQuadricTexture, 85 gluScaleImage, 78 gluSphere, 47, 165 Команды GLUT gluIdleFunc, 135 glutCreateWindow, 35 glutDisplayFunc, 39, 135 glutInit, 35, 134 glutInitDisplaMo de, 134 glutInitDisplayMo de, 35 glutInitWindowPosition, 134 glutInitWindowSize, 35, 134 glutMainLo op, 35, 136 glutMotionFunc, 135 glutMouseFunc, 135 glutPassiveMotionFunc, 135 glutPostRedisplay, 40, 136 glutReshap eFunc, 64, 135 glutSolidCone, 167 glutSolidCub e, 167 glutSolidDo decahedron, 168 glutSolidIcosahedron, 168 glutSolidOctahedron, 168


Предметный указатель
glutSolidSphere, 167 glutSolidTetrahedron, 168 glutSolidTorus, 167 glutWireCone, 167 glutWireCub e, 167 glutWireDo decadedron, 168 glutWireIcosahedron, 168 glutWireOctahedron, 168 glutWireSphere, 167 glutWireTetrahedron, 168 glutWireTorus, 167 Команды WGL wglCreateContext, 148 wglDeleteContext, 149 wglMakeCurrent, 149 Контекст рисования, 148 Контекст устройства, 146 идентификатор, 146 формат пикселей, 147 Объемные модели, 19 Полигональные модели, 20 Экранизация, 18

219


Факультет вычислительной математики и кибернетики Московского государственного университета им. М. В. Ломоносова

АДРЕС: 119992, Москва, ГСП-2, Ленинские горы, 1 МГУ, 2-й учебный корпус.

ТЕЛЕФОНЫ: Приемная комиссия: Подготовительные курсы: Вечерняя математическая школа: Подготовительное отделение: Вечернее специальное отделение для лиц с высшим образованием: Международный отдел факультета Интернет-страница ВМиК МГУ E-mail факультета ВМиК МГУ: 939-54-55 http://www.cs.msu.su e-mail: FAO@cs.msu.su cmc@cs.msu.ru 939-17-73 939-55-90 932-98-08 939-53-74 939-27-17

Информацию о других факультетах МГУ, программах вступительных экзаменов, конкурсе и другую информацию можно посмотреть на странице Московского университета: http://www.msu.ru


НАЧАЛЬНЫЙ КУРС OPENGL
Ю.М. Баяковский, А.В. Игнатенко