OpenGL: раскрой глаза на трехмерную графику
Современный мир уже немыслим без трехмерной
графики - в том числе интерактивной. В свое время было предпринято
множество попыток создать универсальный язык описания трехмерных
сцен. Самой удачной оказалась попытка компании Silicon Graphics - ее
язык OpenGL получил всемирное признание.
Многие из вас знают, что все самые красивые
спецэффекты, а также почти вся промышленная 3D графика рендерится в
формате OpenGL. Этот формат был разработан Silicon Graphics и в
настоящее время стал стандартом де-факто для трехмерного
моделирования. Я попытаюсь дать краткий обзор этой технологии, и во
второй части статьи наш "заслуженный дельфиец" Миша Продан покажет
пару примеров ее использования, разумеется, средствами Delphi.
Принципы
Основная идея OpenGL: графическая библиотека должна
быть аппаратно независимой, но в то же время использовать аппаратные
ускорители, если они доступны. Кроме того, этот язык с самого начала
предусматривал механизм расширения и гибкости - по мере того как
расширения становились "общепринятыми", они становились частью
следующего релиза.
Для любого протокола, будь то сетевой протокол или
язык описания сцен, важным является вопрос уровня абстракции - то
есть того, на каком уровне работает данная система или протокол, что
является входными данными и что выходными, какие компоненты будут
взаимодействовать в качестве поставщиков и приемников данных. Говоря
попросту, нужно определиться по вопросу "что мы делаем и чего не
делаем".
Создатели OpenGL планировали свой язык с явным
намерением создать "виртуальный графический акселератор", так чтобы
примитивы OpenGL максимально соответствовали примитивам современных
графических карт и требовали минимум кода для трансляции из одной
системы команд в другую. Фактически большинство современных
графических процессоров (обычно называемых видеокартами, хотя к
видео они имеют лишь касательное отношение) напрямую воспринимают
OpenGL как язык входного уровня без какой-либо (или с минимумом)
трансляции.
OpenGL оперирует графическими примитивами
"начального уровня", такими как точки трехмерного пространства
(вертексы, вершины), отрезки прямых, выпуклые полигоны и растровые
изображения. Поддерживаются аффинные и проективные преобразования,
вычисление освещения. К "продвинутым" функциям можно отнести мэппинг
текстур (натягивание битовых карт на трехмерные поверхности) и
антиалиасинг (сглаживание цветовых переходов - как локальное, в
рамках отдельного объекта, так и глобальное, по всей сцене).
Предполагается, что приложение более высокого уровня будет выполнять
операции, которых недостает в OpenGL,- например, декомпозицию
невыпуклых полигонов.
С точки зрения программиста, OpenGL - это система
вызовов процедур с передачей им параметров, то есть этот язык
представляет собой Call Level API. Ключевым моментом с точки зрения
производительности, особенно в сетевом окружении, является наличие
двух режимов: пошагового и пакетного. Пакетный группирует команды
описания объектов и режимы в пакет, называемый списком отображения
(display list). Подобная техника применяется, например, при описании
страниц в PostScript или, в несколько другом контексте, при создании
хранимых процедур в SQL. Смысл ясен - инкапсуляция функциональности
(в данном случае - объектов для последующего многократного
использования). При этом можно провести несколько оптимизаций:
предварительно один раз проверить синтаксис, а также кэшировать
готовый объект при передаче по сети на целевой машине.
Недостаток списка отображения проявляется при
частом внесении в него изменений - при этом, понятно, ни один метод
оптимизации не будет работать. Для работы с такими "изменчивыми"
объектами и сценами в OpenGL предусмотрен режим прямого отображения,
когда каждое предложение интерпретируется в порядке поступления, не
дожидаясь закрывающего список тега или какой-то подобной команды на
отрисовку. В практике оба метода нашли широкое применение.
Архитектура
Более глубоко погружаясь в технологию OpenGL, мы
обнаружим стройную и гармоничную архитектуру, общий вид которой
показан на рисунке.
Точно так же, как процессор имеет два типа
конвейеров - для целочисленных вычислений и чисел с плавающей
точкой, OpenGL имеет два конвейера для пиксельных данных и
вертексных операций, то есть для операций с векторными данными.
Каждый из потоков обрабатывается отдельно, до тех пор пока это
возможно - то есть до стадии мэппинга, когда пиксельные растры как
фактуры "натягиваются" на плоскости и более сложные поверхности.
Первый этап - аппроксимация кривых и поверхностей
вычислением полиномов от входных значений. Второй проход оперирует с
примитивами типа точек, отрезков и полигонов - они преобразуются по
правилам аффинных преобразований, совмещаются и сцена отсекается в
подготовке к растрированию.
Растрирование в качестве результата создает список
объектов (точек, отрезков и треугольников) в двумерной плоскости.
Над отдельными объектами может быть выполнена операция
раскрашивания, градиентной заливки или применения мэппинга, то есть
наложения фактуры.
Готовые фрагменты окончательно обрабатываются перед
тем, как они реально будут внесены в frame buffer. В частности,
фрагменты сортируются зависимо от значений "глубины" - и эти
значения сравниваются с известными на предмет рекомпозиции.
Применение блендинга приводит к тому, что прозрачные фрагменты
принимают цвет, состоящий из их собственного и цветов "ниже лежащих"
фрагментов. Дополнительно может быть реализовано маскирование и
другие эффекты.
Пиксельный процессор в ходе растрирования
встраивает двумерные битовые фрагменты прямо в кадр. Часть готового
кадра также может быть прочитана для повторного использования как
массив пикселей - так что данные, отображаемые в буфере, могут стать
частью других сцен.
Приоритеты
При реализации авторы ставили себе пять ориентиров, важных с
точки зрения получаемых результатов.
- Производительность. С самого начала в OpenGL
была заложена "крайне желательная" возможность отрисовки
динамических сцен. Для получения нужных результатов в систему
введено множество параметров, или, как говорят, режимов рисования.
Если некоторый режим или комбинация режимов на данном оборудовании
не в состоянии обеспечить интерактивного взаимодействия и
необходимой частоты обновления сцены, то пользователь или сама
программа должны быть в состоянии отключать так много
дополнительных функций, сколько нужно для получения "живой"
картинки.
- Ортогональность. По возможности все функции
OpenGL являются ортогональными, то есть независимыми. Вы можете
использовать их в произвольной комбинации, например использование
мэппинга не ограничивает возможностей применения светотени.
- Полнота. Насколько это представляется
возможным, OpenGL соответствует набору функций, предоставляемому
современными аппаратными средствами графической акселерации.
OpenGL старается избегать всего, что должно быть реализовано
программно. С другой стороны, по крайней мере, гарантируется
получение рабочей картинки, даже если производительность и не
позволяет получить ее со всеми подробностями. То есть, если что-то
работает на одной платформе, то этот же код будет работать и на
другой - хотя, возможно, и с другим результатом.
- Интероперабельность. В сетевом окружении
важно передавать данные между разными платформами. Поэтому OpenGL
заранее ориентирован на работу в режиме клиент-сервер, даже если и
клиент и сервер расположены на одном компьютере.
- Расширяемость. Поскольку OpenGL рассчитан на
максимальное соответствие возможностям аппаратуры (а аппаратура,
как известно, имеет тенденцию развиваться), то в OpenGL также
встроены механизмы включения новых функций. С другой стороны,
нестабильный интерфейс затрудняет жизнь разработчиков, поэтому
новые возможности накапливаются достаточное время и применяются
согласованно с выходом новой версии.
Функции
Ниже перечислены основные функции OpenGL, о
некоторых из них уже упоминалось. По ним вы можете судить об уровне
языка и используемых примитивах.
- Альфа-канал. Позволяет делать предметы прозрачными, уровень
прозрачности от 0 до 100%.
- Антиалиасинг. Сглаживание цветовых переходов, более
реалистическое изображение.
- Буфер аккумулятора. Дополнительный буфер для 2,5-мерных
эффектов, спецэффектов и глобального сглаживания по всей сцене.
- Градиентная заливка (gouraud shading). Линейно-градиентная
заливка полигонов и отрезков.
- Графические примитивы. В пространстве: точка, отрезок,
полигон, битовое изображение или изображение в другом формате.
- Двойная буферизация. Применяется для сглаживания эффектов
анимации, когда новое изображение строится на заднем плане и потом
отображается целиком. При этом пользователь не видит самого
процесса создания изображения в несогласованном состоянии,
например различных "изнанок объектов", "дыр в пространстве",
"граней мира" и подобных нежелательных деталей.
- Заливка и освещенность фактур. К фактурам применяются эффекты
освещенности и затенения в зависимости от характеристик
"материала". В версии 1.2 реализованы блики поверх текстур.
- Маскирование. Можно маскировать некоторые цвета по трафарету.
- Массивы вершин. Новая возможность версии 1.5 - для повышения
производительности задавать вершины массивами, а не отдельно.
- Обратная связь. Данные после растрирования могут быть
возвращены в приложение вместо передачи из/в frame buffer или
параллельно с ней.
- Пересечения. Автоматическое определение того, пересекает ли
тот или иной объект заданный пространственный регион.
- Пиксельные операции. Масштабирование и другие аффинные
преобразования битовых образов.
- Поддиапазоны. Возможность работать с частью матрицы вершин;
применяется как метод оптимизации.
- Полиноминальные операции. Поддержка неравномерных рациональных
би-сплайнов для описания кривых поверхностей.
- Полноцветное отображение. Представление в режиме RGBA, то есть
тремя цветами и значением альфа-канала. Начиная с версии 1.2,
поддерживаются также схемы BGRA и схемы с упакованными цветами для
быстрой обработки популярных типов графических файлов.
- Пространственные преобразования. Масштабирование, вращение и
перемещение объектов в пространстве.
- Режим индексированных цветов. Представление цветов не
RGB-триплетами, а индексами в таблице цветов. Применяется для
сжатия размена изображений "по глубине цвета" и эффектов быстрой
замены одного цвета другим.
- Режим прямой отрисовки. Рисование по мере поступления команд,
без использования списков отображения.
- Смешивание цветов. Позволяет устанавливать несколько режимов
наложения одного изображения на другое. С помощью этой операции, в
частности, реализуется альфа-канал и другие эффекты.
- Список отображения (display list). Пакет описания объектов
сцены для предварительного разбора и оптимизации кэширования.
- Текстуры. Наложение двухмерных изображений на объемные
поверхности для придания сцене реализма. Начиная с версии 1.2,
поддерживаются трехмерные текстуры. Кроме того, начиная с этой же
версии, поддерживается уровень текстур, позволяющий загружать их
только до определенной степени детализации - в целях экономии
памяти текстур.
- Z-буффер. Понятие об удалении объектов и их частей от
наблюдателя, часть алгоритма удаления скрытых поверхностей.
Ресурсы
Для быстрого и всестороннего "проникновения" идеями
OpenGL вы должны (как минимум) детально изучить две книги,
являющиеся "классикой жанра". Первая из них носит название Синей книги (на ее обложке действительно
преобладает синий цвет) и представляет собой справочник по функциям
и переменным.
Вторая книга (а возможно, по порядку прочтения и
первая) - это OpenGL Programming Guide, так называемая Красная книга.
Красная книга снабжена примерами, на которые я бы
советовал обратить самое пристальное внимание. К слову: указанные
ссылки ведут к устаревшим версиям документации, не описывающим новые
возможности. Новые версии доступны только в печатном виде. Можете
попробовать найти их через сети P2P - однако результаты такого
поиска предсказывать не берусь.
Автор: Арсений Чеботарёв
www.comizdat.com
|