Интерактивные приложения OpenGL

Это стандартное графическое приложением для 2D и 3D-визуализации, разработанного в 1992 году. Opengl поставляется в двух вариантах. Первый из них — «Микрософт OpenGL», который часто включается в «Виндовс» для установки графической карты. Второй — Cosmo OpenGL - предназначен для систем, у которых нет ускоренной видеокарты. Библиотека OpenGL - основное условие работы приложения.

Пользовательский обзор OpenGL

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

OpenGL не зависит от характеристик «Виндовс» каждой операционной системы, но предоставляет специальные подпрограммы для ОС. Она выпускается с огромным перечнем встроенных возможностей, запрашиваемых через API. К ним относятся:

  • скрытое удаление поверхности;
  • альфа-смешение (прозрачность);
  • сглаживание;
  • текстурное картирование;
  • операции с пикселями;
  • просмотр и моделирование трансформаций;
  • атмосферные эффекты (туман и дымка).

Silicon Graphics - разработчики передовых графических рабочих станций - инициировала разработку OpenGL. DEC, Intel, IBM, Microsoft и Sun Microsystems вошли в отраслевую комиссию по обзору архитектуры. Разработка приложений, использующих API OpenGL, не несет никаких затрат, кроме обучения. Microsoft предлагает бесплатную загрузку ее библиотек для своих систем.

Набор модулей для Windows

Приложение доступно на многих системах Win32 и Unix. А f90gl — это реализация публичного домена официальных связей Fortran 90 для OpenGL, оформленная в виде базы данных модулей и библиотек, определяющей необходимые интерфейсы для функциональности программы. Сам f90gl был разработан Уильямом Ф. Митчеллом технологического института Гейтерберга в США. До недавнего времени OpenGL LF9x можно было создавать только в виде статически связанных программ, ориентированных на Visual C.

В настоящее время доступен гораздо более дружелюбный метод благодаря усилиям по переносу, реализованным Lawson B. Wakefield из Великобритании. Эта реализация сделала интерфейс OpenGL доступным в рамках WiSK и Winteracter и была выполнена на добровольной, некоммерческой основе. Для подключения библиотеки OpenGL нужны определенные DLL OpenGL, установленные в каталоге Windows SYSTEM32. К ним относятся следующие:

  • opengl32.dll;
  • glu32.dll;
  • glut32.dll.

Первые две из этих библиотек OpenGL (изучить их перед установкой необходимо), являются стандартной частью Windows разных модификаций и Me. Библиотеки и модули f90gl должны быть установлены в LIB-каталоге LF95:

  • F90GL.LIB;
  • F90GLU.LIB;
  • F90GLUT.LIB;
  • OPENGL32.LIB;
  • GLU32.LIB;
  • GLUT32.LIB;
  • OPENGL.MOD;
  • OPENGL2.MOD;
  • OPENGL_KINDS.MOD;
  • OPENGL_GLINTERFACES.MOD;
  • OPENGL_FWRAP.MOD;
  • OPENGL_GLUINTERFACES.MOD;
  • OPENGL_GLU.MOD;
  • OPENGL_GLUTINTERFACES.MOD;
  • OPENGL_GLUT.MOD;
  • OPENGL_GL.MODd.

Компиляция и связывание программ f90gl требует, чтобы каталог LF95 LIB указывался в пути модуля компилятора и имена библиотек f90gl для связывания.

Библиотеки изображений

DevIL используется для разработчиков. Он поддерживает множество форматов изображений для чтения и записи, несколько компиляторов и ОС («Виндовс», «Линукс», Мас). Библиотека имеет следующий синтаксис:

  1. FreeImage — это кросс-платформенная библиотека OpenGL загрузки изображений с очень широкой поддержкой форматов (включая некоторые HDR-форматы, такие как OpenEXR).
  2. OpenImageIO (OIIO) — это библиотека для чтения и записи изображений, а также множество связанных классов, утилит и приложений. Широко используется в анимационных и VFX-студиях по всему миру, а также встроена в несколько коммерческих продуктах.
  3. SOIL — это кросс-платформенный загрузчик изображений общего пользования, который чрезвычайно мал. C ++, способный загружать текстуры DDS (DDS9 и DDS10) по лицензии MIT.
  4. Glraw предоставляет инструмент командной строки, который преобразует файлы изображений в необработанные, непосредственно содержащие простые текстурные данные.

Импорт активов 3D-файлов

Графическая библиотека OpenGL для импорта активов (Assimp) представлена как библиотека с для импорта разнообразных популярных трехмерных моделей. Самая последняя версия экспортирует 3d-файлы и подходит как конвертер общего назначения. Имеется несколько видов таких библиотек:

  1. Может считывать различные форматы 3D-файлов - COLLADA, собственные файлы Blender3D, Wavefront Obj (.obj) и многие другие. Библиотека lib3ds предназначена для чтения 3ds-файлов.
  2. Open3mod — это средство просмотра модели на базе Windows. Он загружает все форматы файлов, которые поддерживает Assimp, и идеально подходит для быстрой проверки 3D-активов.
  3. AssetKit (In Progress) — библиотека OpenGL импортер/экспортер 3D-ресурсов, утилита, основанная на спецификациях COLLADA/glTF. Главное внимание здесь уделено COLLADA и glTF. Она будет полностью поддерживать форматы 1.4, 1.4.1, 1.5+, а также некоторые другие в качестве библиотеки для загрузки моделей в OpenGL.

Высокопроизводительная 2D/3D-графика

Графическая библиотека OpenGL для Android включает поддержку высокопроизводительной 2D и 3D-графики с открытой библиотекой, в частности API OpenGL ES. Android поддерживает ее как через API-интерфейс инфраструктуры, так и Native Development Kit (NDK). В платформе названной операционной системы есть два фундаментальных класса, которые позволяют создавать и манипулировать графикой с помощью API: GLSurfaceView и GLSurfaceView.Renderer.

Если есть цель использовать OpenGL в приложении для Android, то нужно понимать, как реализовать эти классы в действии. Так, GLSurfaceView может рисовать и манипулировать объектами, используя вызовы API OpenGL аналогично функции SurfaceView. Этот интерфейс определяет методы, необходимые для рисования графики в a GLSurfaceView. И пользователь должен обеспечить реализацию этого интерфейса как отдельный класс и прикрепить к GLSurfaceView экземпляр GLSurfaceView.setRenderer. После того как создан контейнерный вид для OpenGL ES, GLSurfaceView и GLSurfaceView.Renderer, можно начать подключение библиотеки OpenGL и использовать API.

Набор мобильных графических устройств

Реализации приложения различаются для Android-устройств поддерживаемыми расширениями API и включают сжатие текстур и другой набор функций. Android Extension Pack (AEP) поддерживает стандартную базу расширений. Упаковка их вместе способствует последовательному набору функциональности на всех устройствах, позволяя разработчикам в полной мере использовать новейший пакет мобильных графических конструкций.

AEP также улучшает поддержку изображений, буферов хранения шейдеров и счетчиков. Чтобы приложение могло использовать AEP, версия платформы должна поддерживать ее. Нужно также обозначит требование AEP следующим образом: <использует функцию android: name = "android.hardware.opengles.aep" android: required = "true" />

Проверка и выбор версии OpenGL ES

На Android-устройствах доступно несколько версий приложения. Можно указать минимальную версию API, которая требуется приложению в телефоне. Версия API opengl ES 1.0, версия 2.0 и версия 3.0 обеспечивают высокопроизводительные графические интерфейсы для создания 3D-игр, визуализации и пользовательских интерфейсов. Программа для OpenGL ES 2.0 во многом похожа на версию 3.0, представляющую собой надмножество API 2.0 с дополнительными функциями.

Программирование для 1.0 / 1.1 API по сравнению с 2.0 и 3.0 значительно отличается, и поэтому разработчикам следует внимательно изучить некоторые факторы, прежде чем начинать разработку с помощью этих API. Так, в общем, 2 и 3 обеспечивают более быструю графическую производительность, чем API ES 1/1,1. Тем не менее разница в ней может варьироваться в зависимости от устройства Android, на котором работает приложение, из-за различий в реализации аппаратного обеспечения графического конвейера.

Сравнение с драйверами DirectX

В Windows графические драйверы DirectX поддерживаются качественнее, чем OpenGL, несмотря на то что разработчики управляют из более быстрых.

Библиотеки OpenGL и DirectX (история и перспективы их) связаны с «Микрософт», которая фактически выступила против OpenGL. В 2003 году Microsoft заявила, что ей больше не интересны планы OpenGL. Затем в 2005 году они на презентации в SIGGRAPH сделали заявление, что Windows Vista удалит ее поддержку.

Эта кампания вызвала хаос в сообществе OpenGL, после чего многие программисты в области профессиональной графики перешли на DirectX. После того как Vista все же была выпущена, громкие заявления выполнены не были - поставщики создали новые производительные драйверы (ICD), которые восстанавливают встроенную функцию. Open рассылала информационные бюллетени с информацией, что по-прежнему является лучшим приложением. Тем не менее ущерб уже был нанесен, а общественное доверие к OpenGL сильно пошатнулось.

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

  1. Предоставляет возможность использовать функции графики для оперативных систем, в то время как DirectX предоставляет только моментальные элементы из них в новейших версиях «Виндовс». Технология тесселяции, которую Microsoft разработывал для DirectX 11, была расширением OpenGL в течение трех лет. Путем кропотливого труда удалось добиться того, что DirectX 10 и 11 теперь работают так же быстро, как и OpenGL, и поддерживают почти столько же функций. Однако есть одна большая проблема: они не работают в Windows XP, которой до сих пор пользуются много людей.
  2. Кросс-платформенный. Многие пользователи Lugaru работают на Mac, Linux и Windows XP и не могут играть через DirectX. Единственный способ доставить новейшую графику для геймеров Windows XP — через 32bits opengl библиотеки.
  3. Лучше для будущего игр. Это некоммерческий открытый стандарт, созданный для того, чтобы пользователи на любой платформе могли получать высококачественную графику, которую предоставиляет их оборудование. Его развитие разрушается сегодня монополистической атакой корпоративного гиганта, пытающегося доминировать в отрасли. Вот почему Direct3D становится единственным игровым графическим API, поддерживаемым в Windows.

C ++ и настройка Visual Studio

Библиотека OpenGL для c имеет бесплатную версию. Специалисты рекомендуют скомпилировать программы, написанные на ANSI C с OpenGL и GLUT, с помощью Dev-C ++.

Bloodshed Dev-C ++ - это бесплатный компилятор C ++ и среды разработки для операционных систем Windows. Как и большинство таких же технических средств, его можно использовать для компиляции ANSI C. Установив файлы заголовков GLUT и библиотеки, его применяют для написания программ. Для реализации этого проекта можно использовать 32-разрядную или 64-разрядную «Виндовс».

Перед тем как подключить к dev c библиотеку OpenGL, понадобятся заголовки glew, которые можно найти на вебсайте sourceforge Extension Wrangler, и версия freeglut для Visual Studio:

  1. Нажать ссылку внутри пакета freeglut 3.0.0 MSVC.
  2. Ввести имя файла, который нужно скачать.
  3. Загрузить его, в папке с freeglut.
  4. Извлечь и переименовать в freeglut.
  5. Общий каталог для установки: C: \ DEV.
  6. Каталог, в котором находятся проекты: C: \ DEV \ visual-studio-c ++.
  7. Каталог, в котором находятся библиотеки: C: \ DEV \ Lib Visual Studio.
  8. Открыть его и создать пустой проект > «Шаблоны»> Visual C ++> Пустой проект.
  9. Затем написать «Имя»: Shapes2D.
  10. Местоположение: C: \ dev \ visual-studio-c ++ \.
  11. Создать новое решение в OpenGL-библиотеке для Visual Studio. Название решения: BadprogTutorial OK.
  12. Проект Shapes2D создан в решении BadprogTutorial.
  13. Добавить main.cpp> Кликнуть правой кнопкой мыши «Проект»> «Добавить»> «Новый элемент»> Visual C ++> Файл C ++. Написать имя: main.cpp и добавить.
  14. Настроить конфигурации библиотеки GL и OpenGL glut.
  15. Кликнуть мышью проект Shapes2D> «Свойства». В левом верхнем углу раскрывающегося меню найти «Конфигурация» и выбрать все конфигурации (вместо Debug).
  16. Кликнуть мышью на «Свойства конфигурации»> C / C ++> «Общие»> «Дополнительные каталоги вложений». Справа находится раскрывающееся меню, нажать «Изменить...».
  17. Появилось новое окно: «Дополнительные каталоги».
  18. Нажать значок «Новая линия»> кнопку обзора и выбрать две следующие папки: C: \ DEV \ Lib \ Glew-1.12.0 \ . C: \ DEV \ Lib \ freeglut-3.0.0 \ .
  19. Нажать кнопку ОК. Применить использование библиотеки OpenGL, включая библиотеки, библиотечные папки.
  20. Кликнуть правой кнопкой мыши проект Shapes2D> «Свойства» > «Свойства конфигурации»> «Коннектор»> «Общие»> «Дополнительные каталоги библиотек».
  21. Справа находится раскрывающееся меню. Нажать на «Изменить...». Появилось новое окно: «Дополнительные библиотеки».
  22. Нажать значок «Новая линия»> нажать кнопку обзора> выбрать две следующие папки для 64-разрядной версии: C: \ DEV \ Lib \ Glew-1.12.0 \ Lib \ Release \ x64 и C: \ DEV \ Lib \ freeglut-3.0.0 \ Lib \ x64.
  23. Нажать кнопку ОК> применить библиотечные файлы. Кликнуть мышью проект Shapes2D> «Свойства» > «Свойства конфигурации»> «Коннектор»> «Ввод».
  24. Справа находится раскрывающееся меню, нажмите «Изменить...».
  25. Появилось новое окно: «Дополнительные зависимости». Кликнуите по белой области и напишите: freeglut.lib.
  26. Нажать Enter, чтобы перейти к следующей строке: glew32.lib.
  27. Нажать «Применить» и ОК.

Теперь Visual Studio IDE готова работать с OpenGL.

Загрузка Dev-C ++

Эти инструкции были протестированы на большом множестве систем Windows, которые поставляются с файлами, необходимыми для OpenGL, но не для файлов, необходимых для GLUT. Dev-C ++ не работает с Vista от Microsoft.

Процедура загрузки:

  1. Загрузите Dev-C ++ и установите его.
  2. Получите Dev-C ++ 5.0 beta 9.2 (4.9.9.2) (9.0 MB) с Mingw / GCC 3.4.2 (хотя это «бета-версия», она отлично работает).
  3. Теперь нужно нажать на SourceForge, чтобы перейти к списку сайтов загрузки, и выбрать один.
  4. Сохранить этот файл в таком месте, как C: \ Temp.
  5. Когда загрузка будет завершена, нажать кнопку «открыть», чтобы начать процесс установки. Или перейти к C: \ Temp и дважды кликнуть по devcpp4.9.9.2_setup.exe.
  6. Выбрать «типичную» установку. Принять предложенный пункт назначения для установки.
  7. Ответить: «Да», когда установка спрашивает, хотите ли установить Dev-cpp для всех пользователей. На экране появляется сообщение, что установка завершена. Нажать «Готово». Появится первый экран конфигурации.
  8. Выбрать «Английский» и «Новый взгляд». На следующих нескольких экранах нажать «Да». Программа запускается автоматически.
  9. Нажать «Файл», затем создать проект.
  10. Выбрать имя для проекта (например, «myProject»).
  11. Нажать «C Project», «Пустой проект» и ОК.
  12. В окне «Создать новый проект» нажать «Сохранить».
  13. Нажать «Файл / Новый / Исходный файл» и в «Добавить исходный файл в текущий проект» нажать «Да».
  14. Нажать «Файл / Сохранить как» и сохранить файл как «hello.c» (или другое имя). Важно убедиться, что расширение файла.c. С любым другим расширением (например, предлагаемым.cpp) возникнут проблемы с компиляцией.
  15. Нажать «Выполнить / Скомпилировать и запустить». Программа компилирует, запускает и записывает свой вывод в окно DOS.
  16. Попробовать другой способ запуска программы (после ее компиляции) — запустить окно DOS вне системы Dev-Cpp.
  17. Перейти к подкаталогу, в котором содержится проект, и набрать hello.exe.
  18. Найти Dev-C ++, указанный в разделе «Программы» из пускового меню.

Теперь пользователь сможет создавать, компилировать и запускать программы C (и C ++). У него будут файлы, библиотеки и dll для OpenGL (и всех других стандартных пакетов), но не GLUT. GLUT управляет окнами и другими компонентами пользовательского интерфейса, необходимыми для него, и их устанавливают отдельно.

Установка и запуск программы на Windows 7

Платформа выполнения для Visual Studio 2010 - Integrated. Среда (IDE), под управлением Windows 7. Вам нужно загрузить и установить Microsoft Visual C ++ 2010 Express. А после того как Visual C ++ будет успешно установлен, следует выполнить следующие действия:

  1. Загрузить и распаковать файл freeglut-MSVC-2.8.1-1.
  2. Открыть экран приветствия Visual C ++ 2010 из меню «Пуск».
  3. Создать новый проект, выбрав File -> New -> Project.
  4. Выбрать Win32 на панели «Установленные шаблоны», а затем «Консольное приложение Win32» со следующей панели.
  5. Назвать свой проект и выбрать папку, в которую нужно его сохранить.
  6. Снять флажок «Создать каталог для решения».
  7. Нажать ОК, чтобы открыть окно приветствия мастера и «Параметры приложения» для диалогового окна настроек.
  8. Снять флажок «Предварительно скомпилированный заголовок», установить флажок «Пустое проект» и выбрать «Консольное приложение».
  9. Нажать «Готово», чтобы увидеть новое окно проекта библиотеки OpenGL для Windows 7.
  10. Нажать мышью на Source Files и выбрать Add -> New Item, чтобы открыть диалоговое окно.
  11. Выбрать «Код» на панели «Установленные шаблоны» и «Файл C ++» (.cpp) со следующей панели.
  12. Назвать свой файл и нажать «Добавить», чтобы увидеть пустую панель кода в окне проекта с названием «Выбранное имя».
  13. Сохранить и создайть проект, перейдя в Debug -> Build Solution. Затем выполнить программу с помощью Debug -> Start Debugging.

Если графическая карта не поддерживает OpenGL 4.3, то программы, использующие его, могут компилироваться, но не выполняться, поскольку система не может предоставить контекст рендеринга OpenGL 4.3, заданный командой glutInitContextVersion (4. 3) в основной процедуре. В этом случае можно заменить Version 4.3 на 3.3 или даже на 2.1.

Хотя почти все платформы поддерживают OpenGL API, разработчикам по-прежнему необходимо создавать индивидуальные приложения для разных платформ. Это связано с тем, что графика является лишь частью приложения, а другие компоненты по-прежнему отличаются между платформами. Чтобы исправить это, WebApp был разработан для запуска целых программ в веб-браузере, таких как Chrome и Firefox. Так что одна программа может работать на всех платформах с совместимым браузером.

Между тем на стороне клиента все передается «на лету» с серверов, поэтому дальнейшая установка приложения не требуется. Специальный API под названием WebGL также был создан для Интернета и основан на ES, подмножестве OpenGL, разработанном специально для мобильных устройств. Чтобы достичь аналогичной цели для VR, другой API, называемый WebVR, был разработан, чтобы легко довести опыт VR до браузеров, независимо от платформы.

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

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

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

В библиотеке OpenTK функции библиотеки GLUT находятся в классе Glu в пространстве имен Tao .OpenGL (C#). В Object Pascal все функции и процедуры библиотеки GLUT имеют префикс "glu" , что позволяет их отличать от процедур и функций OpenGL .

Для формирования матрицы проекции на основе выбранного фрагмента проекции сцены можно использовать команду PickMatrix библиотеки GLUT :

C#: void gluPickMatrix(double x, double y, double width, double height, int viewport); Object Pascal: procedure gluPickMatrix(x,y,width,height: GLdouble; viewport: PGLint);

Команда PickMatrix библиотеки GLUT изменяет текущую матрицу таким образом, чтобы размер области сцены соответствовал области выбора, определённой в координатах проекции этой сцены. Команды имеет следующие параметры:

  • x, y – горизонтальная и вертикальная координаты области выбора в координатах окна, в котором отображается проекция трехмерной сцены.
  • width, height – ширина и высота выбранной прямоугольной области проекции трехмерной сцены в координатах окна.
  • viewport – массив четырех целочисленных элементов. В C# передается непосредственно массив в качестве параметра, в Object Pascal в качестве параметра передаётся указатель на массив. Массив определяет область вывода проекции трехмерной сцены. Значения массива должны соответствовать координатам области вывода, определённым с помощью команды ViewPort . Элементы этого массива должны иметь следующие значения: 1й и 2й элементы – координаты x и у левого верхнего угла выделенной области в координатах экрана, 3 и 4 элементы – ширина и высота этой области.

Команда должна быть выполнена перед выполнением команд Ortho или Frushtum , с помощью которых формируется матрица проекции.

Перевод библиотеки OpenGL в режим выбора

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

C#: int RenderMode(RenderingMode mode); Object Pascal: function glRenderMode(mode: GLenum): GLint;

Параметр mode определяет режим работы библиотеки OpenGL и может принимать одно из трех значений:

Таблица 10.1. Возможные значения параметра mode команды RenderMode
Описание Значение
Библиотека OpenTK, C# Object Pascal
Режим выбора, данное значение используется для перевода библиотеки в режим выбора. RenderingMode.Select GL_SELECT
Режим формирования изображения сцены. Этот режим используется по умолчанию после инициализации библиотеки OpenGL. Именно в этом режиме выполняется формирование изображения библиотекой OpenGL. RenderingMode.Render GL_RENDER
Режим обратной связи. RenderingMode.Feedback GL_FEEDBACK

После переключения в режим выбора библиотека OpenGL не формирует изображение до тех пор, пока режим не будет изменен на режим формирования изображения сцены с помощью команды RenderMode со значением параметра RenderingMode.Render на C# и GL_RENDER на Object Pascal.

Именование и формирование объектов сцены

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

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

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

C#: void InitNames(); Object Pascal: procedure glInitNames;

Помещение имени в стек выполняется с помощью команды PushName :

C#: void PushName(uint name); Object Pascal: procedure glPushName(name: GLuint);

Имя передается в качестве параметра команды.

Перед использованием стека имен он должен быть инициализирован с помощью команды InitNames . Затем в стек необходимо поместить один элемент с помощью команды PushName . Перед формированием каждого из объектов единственный элемент стека имен будет заменяться на имя формируемого объекта с помощью команды LoadName . Процедура заменяет последний элемент в стеке имен на заданный в качестве параметра. Таким образом, инициализация и использование стека имен схематически можно представить следующим образом:

InitNames; PushName(0); … LoadName(1); //формирование объекта № 1 LoadName(2); //формирование объекта № 2 LoadName(3); //формирование объекта № 3 //и т.д. Листинг 10.7. Схема использования стека имен для выбора объектов

Лабораторная работа № 2.

1. Введение

OpenGL – Open Graphics Library, открытая графическая библиотека. Термин "открытый" – означает независимый от производителей. Имеется спецификация (стандарт) на OpenGL, где все четко задокументировано и описано. Библиотеку OpenGL может производить кто угодно. Главное, чтобы библиотека удовлетворяла спецификации OpenGL и ряду тестов. Как следствие, в библиотеке нет никаких темных мест, секретов, недокументированных возможностей и т. п, те кто программировал под MS Windows или MS DOS понимают о чем я говорю. Библиотеку выпускают такие корпорации, как Microsoft, Silicon Graphics, а также просто группы программистов. Одним из таких примеров служит реализация Mesa. Эту библиотеку написали целый ряд программистов, главным автором является Brian Paul. Библиотека Mesa распространяется в исходных текстах на языке Си и собирается почти для любой операционной системы. Стандарт OpenGL развивается с 1992 года. Он разрабатывается фирмой Silicon Graphics. С тех пор библиотека завоевала огромную популярность и была интегрирована с множеством языков и систем разработки приложений. Вы можете писать программу с использованием OpenGL на Си, С++, Pascal, Java и многих других языках. Основное предназначение OpenGL программирование трехмерной графики.

Библиотека OpenGL представляет собой интерфейс программирования трехмерной графики. Единицей информации является вершина, из них состоят более сложные объекты. Программист создает вершины, указывает, как их соединять (линиями или многоугольниками), устанавливает координаты и параметры камеры и ламп, а библиотека OpenGL берет на себя работу создания изображения на экране. OpenGL идеально подходит для программистов, которым необходимо создать небольшую трехмерную сцену и не задумываться о деталях реализации алгоритмов трехмерной графики. Для профессионалов, занимающихся программированием трехмерной графики, библиотека тоже будет полезной, т. к. она представляет основные механизмы и выполняет определенную автоматизацию. Используя OpenGL можно с легкостью создать трехмерные поверхности, наложить на них текстуры, осветить источниками света, сделать эффект тумана, прозрачности, смешивания цветов, а также наложить трафарет, передвигать объекты сцены, лампы и камеры по заданным траекториям, сделав тем самым анимацию. OpenGL непосредственно не поддерживает работу с устройствами ввода, такими как мышь или клавиатура, т. к. эта библиотека является платформенно независимой. Но можно задействовать функции конкретной операционной системы, под которую вы пишите свою программу или воспользоваться надстройками над OpenGL, такими как библиотеки GLUT или GLAUX.

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

Самым простым объектом, с помощью которого можно увидеть всю мощь OpenGL, является сфера. Можно попытаться ее изобразить. Для этого надо создать новый проект в VisualC++, выполнив следующие действия:

— запустить Visual C++;

— выполнить команду File | New…;

— в открывшемся диалоговом окне выбрать тип проекта Win32 Application, в поле Project Name указать имя проекта, а в поле Location – папку в которой будет находиться проект;

— нажать кнопку OK. Затем, ничего не изменяя, – кнопку Finish и еще раз OK;

— скопировать в папку проекта два файла Sample. cpp и Sample. h (выдаются преподавателем);

— подключить эти два файла к проекту выполнив команду Project | Add To Project | Files…;

— вставьте в функцию Display следующий код:

GlColor3d(1,0,0);

AuxSolidSphere(1);

— создать exe-модуль (F7).

Поясним назначение вставленных двух функций. Функция glColor3d устанавливает текущий цвет, которым будут рисоваться фигуры. Тут нужно пояснить, как устанавливается цвет и общую философию в названии функций OpenGL. Цвет устанавливается четырьмя параметрами: красный, синий, зеленый и прозрачность. Эти параметры варьируются в диапазоне от нуля до единицы. Четвертый параметр нам пока не нужен, поэтому мы вызвали glColor с тремя параметрами. В этом случае, значение четвертого параметра, прозрачности, по умолчанию считается равным единице, т. е. абсолютно непрозрачным, ноль – будет абсолютно прозрачным. Применяется следующий синтаксис вызова функций – FuncionName[тип параметров].

Доступны следующие типы:

B – GLbyte байт;

S – GLshort короткое целое;

I – GLint целое;

F – GLfloat дробное;

D – GLdouble дробное с двойной точностью;

Ub – GLubyte беззнаковый байт;

Us – GLushort беззнаковое короткое целое;

Ui – GLuint беззнаковое целое;

V – массив из n параметров указанного типа;

В нашем случае – glColor3d – означает, что в функцию передается три параметра типа GLdouble. Также можно было вызвать glColor3i, т. е. три параметра типа GLint. Если тип параметров короткое целое, целое, байт или длинное, то компонента цвета приводится к диапазону . Приведение к этому диапазону осуществляется по следующим правилам. В случае беззнакового типа возможное наибольшее значение приводится к единице, ноль к нулю. В случае знакового максимальное значение приводится к единице или к минус единице, а минус единица будет приведена к единице. На практике обычно пользуются одним из трех случаев, рассмотренных в качестве примера ниже. Например, для беззнакового байта приведение будет осуществлено по следующей формуле: значение_переменной_хранимой_в_байте/255, т. к. 255 максимальное число, хранимое в одном байте. Функция glColor3dv означает, что в качестве параметров передается массив из трех элементов типа GLdouble. Например:

Double array = {0.5, 0.75, 0.3};

GlColor3dv(array);

GlColor3ub(200,100,0); // приводится к

// 200/256, 100/256, 0,256

GlColor3d(0.25,0.25,0); // темно-желтый

GlColot3ub(0,100,0); // темно-зеленый

GlColor3ub(0,0,255); // синий

3. Простые объекты. Общие положения

Точки, линии, треугольники, четырехугольники, многоугольники –простые объекты, из которых состоят любые сложные фигуры. OpenGL непосредственно не поддерживает функций для создания таких сложных объектов как сфера, цилиндр тор и др., т. е. таких функций нет в opengl32.dll. Эти функции есть в библиотеки утилит glu32.dll, и устроены они следующим образом. Для того чтобы нарисовать сферу функция auxSolidSphere использует функции из библиотеки glu32.dll, а те в свою очередь, используют базовую библиотеку opengl32.dll и из линий или многоугольников строят сферу. Примитивы создаются следующим образом:

GlBegin(mode); // указываем, что будем рисовать

glVertex(…); // первая вершина

… // тут остальные вершины

glVertex(…); // последняя

//вершина

GlEnd(); // закончили рисовать примитив

Сначала необходимо указать начало рисования – glBegin с соответствующим параметром.

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

GlVertex2d(x, y); // две переменных типа double

GlVertex3d(x, y,z); // три переменных типа double

GlVertex2dv(array); // массив из двух переменных типа

GlVertex3d(array); // массив из трех переменных типа

Void glEnd(void);

Указывает на конец рисования объектов типа, указанного в glBegin. Далее подробно разберем создание всех примитивов.

Таблица 1.

Возможные значения mode

Значение

Описание

Каждый вызов glVertex задает отдельную точку.

Каждая пара вершин задает отрезок.

Рисуется ломанная.

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

Каждые три вызова glVertex задают треугольник.

GL_TRIANGLE_STRIP

Рисуются треугольники с общей стороной.

То же самое, но по другому правилу соединяются вершины.

Каждые четыре вызова glVertex задают четырехугольник.

Четырехугольники с общей стороной.

Многоугольник.

3.1. Точки

Можно нарисовать сколько угодно точек, вызывая glVertex3d, и тем самым, устанавливая новую точку. При создании точек можно изменять следующие параметры. Можно вызывать glColor3d внутри glBegin/glEnd. Размер точки можно устанавливать с помощью функции:

Void glPointSize(GLfloat size);

Режим сглаживания можно устанавливать вызовом функции

GlEnable(GL_POINT_SMOOTH);

Отключается соответственно вызовом glDisable(GL_POINT_SMOOTH). Последние функции – glPointSize и glEnable/glDisable надо вызывать вне glBegin/glEnd, иначе они будут проигнорированы. Функции glEnable/glDisable включают/выключают множество опций, но следует учитывать, что некоторые опции влекут за собой большие вычисления и, следовательно, изрядно затормаживают приложение, поэтому без надобности не стоит их включать.

// рисуем точки

GlBegin(GL_POINTS);

glColor3d(1,0,0);

glVertex3d(-4.5,4,0); // первая точка

glColor3d(0,1,0);

glVertex3d(-4,4,0); // вторая точка

glColor3d(0,0,1);

glVertex3d(-3.5,4,0); // третья

GlBegin(GL_POINTS);

glColor3d(1,0,0);

glVertex3d(-2,4,0); // первая точка

glColor3d(0,1,0);

glVertex3d(-1,4,0); // вторая точка

glColor3d(0,0,1);

glVertex3d(0,4,0); // третья

GlPointSize(10);

GlEnable(GL_POINT_SMOOTH);

GlBegin(GL_POINTS);

glColor3d(1,0,0);

glVertex3d(2,4,0); // первая точка

glColor3d(0,1,0);

glVertex3d(3,4,0); // вторая точка

glColor3d(0,0,1);

glVertex3d(4,4,0); // третья

GlDisable(GL_POINT_SMOOTH);

3.2. Линии

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

Void glLineStipple(GLint factor, GLushort pattern);

Второй параметр задает саму маску. Например, если его значение равно 255(0x00FF), то чтобы вычислить задаваемую маску воспользуемся калькулятором. В двоичном виде это число выглядит так: 0000000011111111, т. е. всего 16 бит. Старшие восемь установлены в ноль, значит, тут линии не будет. Младшие установлены в единицу, тут будет рисоваться линия. Первый параметр определяет, сколько раз повторяется каждый бит. Скажем, если его установить равным 2, то накладываемая маска будет выглядеть так:

GlLineWidth(1); // ширину линии

// устанавливаем 1

GlBegin(GL_LINES);

glColor3d(1,0,0); // красный цвет

glVertex3d(-4.5,3,0); // первая линия

glVertex3d(-3,3,0);

glColor3d(0,1,0); // зеленый

glVertex3d(-3,3.3,0); // вторая линия

glVertex3d(-4,3.4,0);

GlLineWidth(3); // ширина 3

GlBegin(GL_LINE_STRIP); // см. ниже

glColor3d(1,0,0);

glVertex3d(-2.7,3,0);

glVertex3d(-1,3,0);

glColor3d(0,1,0);

glVertex3d(-1.5,3.3,0);

glColor3d(0,0,1);

glVertex3d(-1,3.5,0);

GlEnable(GL_LINE_SMOOTH);

GlEnable(GL_LINE_STIPPLE); // разрешаем рисовать

// прерывистую линию

GlLineStipple(2,58360); // устанавливаем маску

// пояснения см. ниже

GlBegin(GL_LINE_LOOP);

glColor3d(1,0,0);

glVertex3d(1,3,0);

glVertex3d(4,3,0);

glColor3d(0,1,0);

glVertex3d(3,2.7,0);

glColor3d(0,0,1);

glVertex3d(2.5,3.7,0);

GlDisable(GL_LINE_SMOOTH);

GlDisable(GL_LINE_STIPPLE);

3.3. Треугольники

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

Void glPolygonMode(

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

Таблица 2.

Значения параметров функции glPolygonMode

Первый параметр указывает, для каких сторон применяется опция, заданная вторым параметром. Треугольники можно рисовать, передав GL_TRIANGLE_STRIP или GL_TRIANGLE_FAN в glBegin. В первом случае первая, вторая и третья вершины задают первый треугольник. Вторая, третья и четвертая вершина — второй треугольник. Третья, четвертая и пятая вершина — третий треугольник и т. д. Вершины n, n+1 и n+2 определят n-ый треугольник. Во втором случае первая, вторая и третья вершина задают первый треугольник. Первая, третья и четвертая вершины задают второй треугольник и т. д. Вершины 1, n+1, n+2 определяют n-ый треугольник. Далее следует пример с комментариями.

GlPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // см. выше

GlBegin(GL_TRIANGLES);

glColor3d(1,0,0); // рисуем треугольник

glVertex3d(-4,2,0);

glVertex3d(-3,2.9,0);

glVertex3d(-2,2,0);

//рисуем проволочные треугольники

GlBegin(GL_TRIANGLE_STRIP); // обратите внимание на

// порядок вершин

glColor3d(0,1,0);

glVertex3d(1,2,0);

glVertex3d(0,2.9,0);

glVertex3d(-1,2,0);

glVertex3d(0,1.1,0);

GlEnable(GL_LINE_STIPPLE);

GlPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

GlBegin(GL_TRIANGLE_FAN);

glColor3d(0,0,1);

glVertex3d(4,2,0);

glVertex3d(2.6,2.8,0);

glVertex3d(2,2,0);

glVertex3d(3,1.1,0);

GlDisable(GL_LINE_STIPPLE);

3.4. Четырехугольники и многоугольники

Четырехугольники рисуются вызовом функции glBegin с параметром GL_QUADS или GL_QUAD_STRIP. Для первого случая каждые четыре вершины определяют свой четырехугольник. Во втором случае рисуются связанные четырехугольники. Первая, вторая, третья и четвертая вершина определяют первый четырехугольник. Третья, четвертая, пятая и шестая вершина — второй четырехугольник и т. д. (2n-1), 2n, (2n+1) и (2n+2) вершины задают n-ый четырехугольник. Многоугольники задаются вызовом glBegin с параметром GL_POLYGON. Все вершины определяют один многоугольник. Для многоугольников можно задавать стили при помощи выше описанной функции glPolygonMode, толщину линии, толщину точек и цвет.

4. Переход к новым координатам

В предыдущем разделе вы научились рисовать примитивные трехмерные объекты. Но проблема в том, что они рисуются только в начале координат, т. е. в точке (0,0,0). Для того чтобы изобразить объект в точке (x0,y0,z0), надо переместить начало координат в эту точку, т. е. надо перейти к новым координатам. Эта процедура довольно распространенная при программировании графики и анимации. Часто, бывает очень удобно, сместить координаты в новую точку и повернуть их на требуемый угол, и ваши расчеты резко упростятся. Для перехода к новым координатам в OpenGL есть две функции:

Void glTranslated(Dx, Dy, Dz);

Void glRotated(j, x0,y0,z0);

Первая функция сдвигает начало системы координат на (Dx, Dy, Dz). Вторая — поворачивает на угол j против часовой стрелки вокруг вектора (x0,y0,z0). Теперь, стоит сказать еще о двух очень важных функциях:

Void glPushMatrix();

Void glPopMatrix();

Они предназначены для сохранения и восстановления текущих координат. Часто бывает неудобно переходить от одной системы координат к другой и помнить все переходы. Гораздо удобнее с помощью glPushMatrix() сохранить текущие координаты, потом сдвигаться, вертеться, как угодно, а после, вызовом glPopMatrix вернуться к старым координатам. Теперь можно поэкспериментировать. Рассмотрим сдвиг координат. Вставьте в функцию display следующий код:

GlTranslated(1.4,0,0);// сдвигаемся по оси Х на 1.4

GlColor3d(0,1,0);

AuxSolidSphere(0.5); // рисуем сферу в (1.4,0,0)

// в абсолютных координатах

GlTranslated(1,0,0); // еще раз сдвигаемся

GlColor3d(0,0,1);

AuxSolidSphere(0.3);

GlPopMatrix(); // возвращаемся к старой системе

// координат

GlColor3d(1,0,0);

AuxSolidSphere(0.75); // рисуем сферу в точке (0,0,0)

// в абсолютных координатах

5. Поворот координат

Теперь рассмотрим вращение координат. В функцию display вставьте следующий код:

GlColor3d(1,0,0);

AuxSolidCone(1, 2); // рисуем конус в центре координат

GlPushMatrix(); // сохраняем текущие координаты

glTranslated(1,0,0); // сдвигаемся в точку (1,0,0)

glRotated(75,1,0,0); // поворачиваем систему

// координат на 75 градусов

glColor3d(0,1,0);

auxSolidCone(1, 2); // рисуем конус

GlPopMatrix(); // возвращаемся к старым координатам

Как видите, конус повернулся в абсолютных координатах. Так что, для того, чтобы нарисовать фигуру не в начале координат, надо:

· сдвинуть(glTranslated), повернуть(glRotated);

· нарисовать то, что хотели;

· вернуться к старым координатам.

Вызовы glPushMatrix/PopMatrix могут быть вложенными, т. е.:

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

GlGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &n);

Printf("n=%d ",n);

Спецификация на OpenGL гарантирует, что глубина стека не может быть меньше 32.

6. Построение поверхностей

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

GLUquadricObj * qobj,

GLdouble radius,

Void gluCylinder(

GLUquadricObj *qobj,

GLdouble baseRadius,

GLdouble topRadius,

GLdouble height,

GLUquadricObj *qobj,

GLdouble innerRadius,

GLdouble outerRadius,

Void gluPartialDisk(

GLUquadricObj *qobj,

GLdouble innerRadius,

GLdouble outerRadius,

GLdouble startAngle,

GLdouble sweepAngle

В начале занятия вы научились строить трехмерные объекты с помощью функций из библиотеки Auxilary Library. Функции auxSphere, auxCylinder и auxCone просто вызывают gluSphere и gluCylinder. В auxCylinder и auxCone фирмы Microsoft имеются баги. Здесь будет подробно рассмотрено построение сфер и цилиндров, так что потребность в auxCylinder и auxCone отпадет.

Первым параметром для gluSphere, gluCylinder, gluDisk и gluPartialDisk является указатель на объект типа GLUquadricObj. Далее следуют параметры непосредственно создаваемой фигуры. Для сферы – это радиус; для цилиндра – радиус нижнего основания, радиус верхнего основания и высота; для диска – внутренний радиус, внешний радиус и для частичного диска – внутренний радиус, внешний радиус, угол, с которого начинать рисовать, длина дуги в градусах, которую рисовать. Последние два параметра у всех этих функций одинаковы. Это число разбиений вокруг оси Z и число разбиений вдоль оси Z. Как известно, все сложные объекты состоят из простых: точек, линий и многоугольников. Понятно, что нарисовать (создать) идеально гладкую сферу или цилиндр невозможно. Поэтому строится приближение из плоскостей. Для этого и нужно указать количество разбиений. Чем больше разбиение, тем лучше будет выглядеть ваш объект. Однако, задавать здесь число с шестью нулями не стоит. Это лишено всякого смысла. Оптимальным является число от 10 до 20. Чем больше объект, тем больше нужно разбиений. Число разбиений (вдоль и поперек) лучше выставлять одинаковыми.

Сначала необходимо создать объект типа GLUquadricObj с помощью функции

GLUquadricObj * gluNewQuadric(void);

Затем нужно установить свойства с помощью функции

Void gluQuadricDrawStyle(

GLUquadricObj *qobj,

Glenum drawStyle

Доступны стили:

GLU_FILL – рисуется сплошной объект;

GLU_LINE – проволочный объект;

GLU_POINT – рисуются только точки.

Удалить созданный объект можно, воспользовавшись функцией

Void gluDeleteQuadric(GLUquadricObj * state);

Теперь можно поэкспериментировать. Измените функцию display следующим образом.

Void display(void)

GLUquadricObj * quadObj;

// создаем новый объект для создания сфер и цилиндров

quadObj = gluNewQuadric();

glColor3d(1,0,0);

// устанавливаем стиль: сплошной

gluQuadricDrawStyle(quadObj, GLU_FILL);

// рисуем сферу радиусом 0.5

gluSphere(quadObj, 0.5, 10, 10);

glTranslated(-2,0,0); // сдвигаемся влево

glRotated(45, 1,0,0); // поворачиваем

glColor3d(0,1,0);

// устанавливаем стиль: проволочный

gluQuadricDrawStyle(quadObj, GLU_LINE);

gluCylinder(quadObj, 0.5, 0.75, 1, 15, 15);

gluDeleteQuadric(quadObj);

auxSwapBuffers();

7. Плоскости отсечения

Если требуется нарисовать сферу или любой другой объект урезанным, то это можно сделать с помощью плоскости отсечения. Плоскостей отсечения может быть шесть. По умолчанию они все запрещены. Плоскость отсечения включается командой glEnable(GL_CLIP_PLANE0). Ноль на конце GL_CLIP_PLANE означает нулевую плоскость; можно указать один, два, три и т. д. Сама плоскость устанавливается функцией

Void glClipPlane(

const GLdouble *equation

Первый аргумент этой функции – это плоскость, второй – это массив из четырех элементов, в котором хранятся коэффициенты (A, B, C, D) уравнения плоскости: A*x + B*y + C*z + D = 0. Измените функцию display, как показано ниже.

Void display(void)

GLdouble equation = {-1,-0.25,0,2};

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_CLIP_PLANE0);

glClipPlane(GL_CLIP_PLANE0, equation);

glColor3d(1,0,0);

auxSolidSphere(3);

glDisable(GL_CLIP_PLANE0);

auxSwapBuffers();

8. Задания

1. Нарисовать куб представляющий собой пространство RGB. Вершины куба имеют цвета: R – красный, G – зеленый, B – синий, C – голубой, M – пурпурный, Y – желтый, W – белый, K – черный. Цвет каждого ребра плавно изменяется от цвета одной вершины до цвета другой.

После того, как куб нарисован, осуществить сдвиг его так, чтобы начало координат совпало с центром куба, а затем поворот вокруг оси OX на угол 30° и вокруг оси OZ на угол -20°.

2. Нарисовать сцену, в которой в начале координат изображается сфера радиуса r. На расстоянии R1 от первой сферы в некоторой точке (x1, y1, 0) изображается сфера с радиусом r1. От нее на расстоянии R2 в некоторой точке (x2, y2, 0) изображается сфера радиуса r2.

После того как сцена нарисована необходимо ее «оживить», т. е. заставить вращаться сферу r1 вокруг сферы r, а сферу r2 вокруг r1. Для этого необходимо объявить глобальные переменные f1 и f2 – углы поворота соответственно r1 вокруг r и r2 вокруг r1. Затем перед каждым выводом инкрементировать f1f2 на постоянные величины и вычислять x1, y1, x2, y2 по следующим формулам.

В этой главе рассмотрим рендеринг трехмерной графики с помощью библиотеки OpenGL, изучим библиотеки GLU и GLUT (вместо последней иод Linux используется библиотека FreeGLUT), разберем процесс загрузки текстур с помощью библиотек SOIL и DevIL.

Как уже отмечалось в гл. 9, программисты графики обычно не работают напрямую с GPU. Это связано как с тем, что существует много различных GPU, так и с тем, что низкоуровневая работа с GPU довольно сложна и обычно ею занимаются разработчики драйверов. Вместо этого используют различные API, предоставляющие некоторый интерфейс более высокого уровня для работы с GPU. Этот интерфейс абстрагируется от конкретного GPU (вся работа с которым идет через драйвер, обычно поставляемый производителем GPU), что позволяет писать переносимый код, который будет работать с различными GPU. Также подобный API скрывает от программиста ряд низкоуровневых деталей работы с GPU.

Основными API для программирования трехмерной графики на данный момент являются OpenGL и Dircct3D. Последний ориентирован только на платформу Microsoft Windows. В этой книге рассмотрены основы работы с OpenGL. Это кроссплатформен- ный API, поддерживающий все основные операционные системы (Windows, Linux, Mac OS X) и позволяющий работать с большим количеством различных GPU.

Существует версия API - OpenGL ES, предназначенная для работы на мобильных устройствах. С ее помощью можно делать трехмерную графику для платформ iOS и Android. Кроме того, существует WebGL - библиотека, позволяющая использовать OpenGL ES прямо в окне браузера, применяя для этого javascript. Также существуют привязки для OpenGL, позволяющие работать со всеми основными языками программирования, благодаря чему можно легко использовать OpenGL практически из любого языка программирования.

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

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

На практике все выполняемые команды OpenGL буферизуются и уже потом поступают в очередь для передачи на GPU. Таким образом, выполнение CPU команды говорит только о том, что данная команда попала в буфер или была добавлена в очередь; вполне возможно, что GPU ее еще не начал выполнять. В то же время OpenGL можно рассматривать как конечный автомат - у него есть свое состояние. Единственный способ изменить это состояние - использовать команды OpenGL. Между командами состояние OpenGL не изменяется.

Важным понятием в OpenGL являются буферы (рис. 10.1). Для того чтобы осуществлять рендеринг, должны быть созданы необходимые буферы. Буфер цвета используется всегда и для каждого пиксела хранит его цвет как 24-битовое число в формате RGB (по 8 бит на каждый из базовых цветов - красный, зеленый и синий) или как 32-битовое в формате RGBA (к стандартным трем компонентам добавляется четвертая компонента - альфа, задающая непрозрачность).

При использовании метода г-буфера для удаления невидимых поверхностей нужно для каждого пиксела хранить соответствующее ему значение глубины (обычно значение глубины хранится как 16-, 24- и 32-битовое целое число). Соответственно, все значения глубины, взятые вместе, образуют буфер глубины. Также можно использовать буфер трафарета , буфер накопления.

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

Обработка данных в OpenGL основана на конвейере рендеринга (см. рис. 9.1). Конвейер определяет основные стадии обработки поступающих данных. Как именно данные будут обрабатываться, зависит от параметров состояния OpenGL, но сами эти стадии и порядок их прохождения строго зафиксированы.

Рис. 10.1.

Для современных GPU две части этого конвейера представлены с помощью программ, выполняющихся на GPU, - шейдеров. Далее будем рассматривать OpenGL версии 2, в которой эти программы необязательно задавать явно: существуют шейдеры, которые работают по умолчанию (г.е. в случае, когда программист явно не задал соответствующие шейдеры). Начиная с версии 3, OpenGL требует обязательного задания шейдеров и частично нарушает совместимость с предыдущими версиями, именно поэтому мы будем рассматривать версию OpenGL 2.

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

OpenGL использует матрицы 4x4 для преобразования вершин - модельно-видовую матрицу проектирования (рис. 10.2). Если вершинный шейдер не задан явно, то используется вершинный шейдер по умолчанию, который умножает координаты вершины (в виде вектора в однородных координатах) сначала на модельновидовую матрицу, а затем - на матрицу проектирования.

После этого происходит сборка примитивов и их отсечение: все части каждого примитива, выходящие за пределы видимой области {viewing frustum) автоматически обрезаются так, что на следующую стадию конвейера переходят примитивы, полностью содержащиеся внутри области видимости. Далее фиксированная часть конвейера выполняет перспективное деление - вектор в однородных координатах делится на свою четвертую компоненту.


Рис. 10.2.

Если изначально координаты были заданы в своей системе координат, то умножение на модельно-видовую матрицу переводит их в систему координат камеры. Далее умножение на матрицу проектирования приводит координаты в пространство отсечения (clip space). После выполнения перспективного деления получаем нормализованные координаты устройства (normalized device coordinates).

Заключительный шаг - перевод нормализованных координат в координаты в окне, выражаемые в пикселах.

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

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

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

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

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

Если вы пишете программу, использующую OpenGL на С (или C++), то прежде всего необходимо включить следующий заголовочный файл:

Для обеспечения совместимости и переносимости кода OpenGL вводит ряд своих типов данных, имя каждого из этих типов начинается с префикса GL. GLint соответствует стандартному типу целых чисел, тип GLuint - стандартному типу беззнаковых целых чисел, a GLfloat - типу float. Также OpenGL использует несколько специальных типов, таких как GLsizei, обозначающий тип, используемый для задания размера, и GLclampf, используемый для задания значений с плавающей точкой, лежащих на отрезке .

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

В библиотеке OpenGL (а также в идущих с ней в комплекте библиотеках GLU и GLUT) принято использовать довольно простое соглашение об именовании констант и функций. Имена всех команд (функций) OpenGL начинаются с префикса gl (для функций из библиотек GLU и GLUT - с glu и glut соответственно).

Имена всех констант начинаются с GL_ (соответственно с GLU_ и GLUTJ.

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

glCommand{1 2 3 4}{b s i f d ub us ui}{v}

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

Так, в команде glVertex2i два целочисленных аргумента, в команде glColor3f - три аргумента типа float, а в команде glColor4ubv - четыре аргумента типа unsigned byte, переданных в виде массива (т.е. функция при вызове получает всего один аргумент - адрес массива).

OpenGL является на данный момент одним из самых популярных программных интерфейсов (API) для разработки приложений в области двумерной и трехмерной графики. Стандарт OpenGL был разработан и утвержден в 1992 году ведущими фирмами в области разработки программного обеспечения, а его основой стала библиотека IRIS GL, разработанная Silicon Graphics.

На данный момент реализация OpenGL включает в себя несколько библиотек (описание базовых функций OpenGL, GLU,GLUT,GLAUX и другие), назначение которых будет описано ниже.

Характерными особенностями OpenGL, которые обеспечили распространение и развитие этого графического стандарта, являются:

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

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

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

Основные возможности OpenGL

    Набор базовых примитивов: точки, линии, многоугольники и т.п.

    Видовые и координатные преобразования

    Удаление невидимых линий и поверхностей (z-буфер)

    Использование сплайнов для построения линий и поверхностей

    Наложение текстуры и применение освещения

    Добавление специальных эффектов: тумана, изменение прозрачности,сопряжение цветов (blending), устранение ступенчатости (anti-aliasing).

Как уже было сказано, существует реализация OpenGL для разных платформ, для чего было удобно разделить базовые функции графической системы и функции для отображения графической информации и взаимодействия с пользователем. Были созданы библиотеки для отображения информации с помощью оконной подсистемы для операционных систем Windows и Unix (WGL и GLX соответственно), а также библиотеки GLAUX и GLUT, которые используются для создания так называемых консольных приложений.

Библиотека GLAUX уступает по популярности написанной несколько позже библиотеке GLUT, хотя они предоставляют примерно одинаковые возможности. В состав библиотеки GLU вошла реализация более сложных функций, таких как набор популярных геометрических примитивов (куб, шар, цилиндр, диск), функции построения сплайнов, реализация дополнительных операций над матрицами и т.п. Все они реализованы через базовые функции OpenGL.

Архитектура и особенности синтаксиса

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

    Аппроксимация кривых и поверхностей

    Обработка вершин и сборка примитивов

    Растеризация и обработка фрагментов

    Операции над пикселями

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

    Передача данных в буфер кадра

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

ИНИЦИАЛИЗАЦИЯ БИБЛИОТЕКИ OpenGL В C++

Первым делом нужно подключить заголовочные файлы:

#include

#include

#include

· gl.h и glu.h содержат прототипы основных функций OpenGL определённых в opengl32.dll и glu32.dll.

· glaux.h содержит вспомогательные (auxiliary) функции (glaux.dll).

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

BOOL bSetupPixelFormat(HDC hdc)

PIXELFORMATDESCRIPTOR pfd, *ppfd;

int pixelformat;

ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);

ppfd->nVersion = 1;

ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

ppfd->dwLayerMask = PFD_MAIN_PLANE;

ppfd->iPixelType = PFD_TYPE_RGBA;

ppfd->cColorBits = 16;

ppfd->cDepthBits = 16;

ppfd->cAccumBits = 0;

ppfd->cStencilBits = 0;

if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0)

MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);

if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)

MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);

Структура PIXELFORMATDESCRIPTOR сказать надо.

cColorBits - глубина цвета

cDepthBits - размер буфера глубины (Z-Buffer)

cStencilBits - размер буфера трафарета (мы его пока не используем)

iPixelType - формат указания цвета. Может принимать значения PFD_TYPE_RGBA (цвет указывается четырьмя параметрами RGBA - красный, зленный, синий и альфа) и PFD_TYPE_COLORINDEX (цвет указывается индексом в палитре).

Функция ChoosePixelFormat() подбирает формат пикселей и возвращает его дескриптор, а SetPixelFormat() устанавливает его в контексте устройства (dc).

После того как в контексте устройства установлен формат пикселей, нужно создать контекст воспроизведения (Rendering Context) для этого в OpenGL определены следующие функции:

HGLRC wglCreateContext(HDC hdc);

BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc);

В объявлении класса формы в области private необходимо добавить следующее:

ghRC - указатель на контекст воспроизведения (Rendering Context)

ghDC - дескриптор устройства (для нас - просто указатель на окно)

Процедура Draw будет отвечать за рисование.

void __fastcall TForm1::FormCreate(TObject *Sender)

ghDC = GetDC(Handle);

if (!bSetupPixelFormat(ghDC))

ghRC = wglCreateContext(ghDC);

wglMakeCurrent(ghDC, ghRC);

glClearColor(0.0, 0.0, 0.0, 0.0);

FormResize(Sender);

glEnable(GL_COLOR_MATERIAL);

glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

float p={3,3,3,1},

glLightfv(GL_LIGHT0,GL_POSITION,p);

glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,d);

glViewport(0, 0, Width, Height);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glOrtho(-5,5, -5,5, 2,12);

gluLookAt(0,0,5, 0,0,0, 0,1,0);

glMatrixMode(GL_MODELVIEW);

glClearColor() устанавливает цвет, которым будет заполняться экран при очищении. У этой процедуры - 4 параметра, что соответствует RGBA. Вместо нее можно написать glClearIndex(0.0) . Эта процедура устанавливает индекс цвета в палитре.

glViewport() устанавливает область вывода - область, в которую OpenGL будет выводить изображение.

glMatrixMode() устанавливает режим матрицы видового преобразования.

glLoadIdentity() заменяет текущую матрицу видового преобразования на единичную.

glOrtho() устанавливает режим ортогонального (прямоугольного) проецирования. Это значит, что изображение будет рисоваться как в изометрии. 6 параметров типа GLdouble (или просто double): left, right, bottom, top, near, far определяют координаты соответственно левой, правой, нижней, верхней, ближней и дальней плоскостей отсечения, т.е. всё, что окажется за этими пределами, рисоваться не будет. На самом деле эта процедура просто устанавливает масштабы координатных осей. Для того чтобы установить перспективное проецирование, используются процедуры glFrustum() и gluPerspective().

gluLookAt() устанавливает параметры камеры: первая тройка - её координаты, вторая - вектор направления, третья - направление оси Y.

В OpenGL всё включается и выключается (разрешается и запрещается) процедурами glEnable() и glDisable().

glLightfv() устанавливает свойства "лампочек": позицию и направление света.

После того, как завершена работа с OpenGL, нужно освободить занятые ресурсы: освободить контекст, вызвав wglMakeCurrent с параметром ноль для идентификатора контекста OpenGL и разрушить этот контекст функцией wglDeleteContext. Кроме того нужно удалить дескриптор ghDC. Так как обычно работу с OpenGL завершается при завершении работы приложения, то соответствующий код нужно поместить в FormClose:

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

wglMakeCurrent(ghDC,0);

wglDeleteContext(ghRC);

ReleaseDC(Handle, ghDC);

ЗАКЛЮЧЕНИЕ

За время прохождения производственной практики с 5 июля по 31 июля 2011 г. в ЗАО «Транзас», Авиационное направление в отделе программирования, я ознакомился с работой отдела программирования. Ознакомился с устройством и функционированием комплексных авиа тренажеров, разрабатываемых в ЗАО «Транзас». Я узнал о такой системе визуализации ландшафтов и различных объектов, как «Аврора». Я получил первоначальные практические навыки и умения, необходимые для разработки приложений и программного обеспечения с помощью современного высокоуровневого языка программирования и графической библиотеки.