Open GL - статьи

         

Архитектура


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

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

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

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

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

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



Что будем рисовать


Конечно, можно было нарисовать простую пирамиду или же куб. Но мы сделаем большее - нарисуем "признание в любви"** (рис.1). Специально для этого методом "научного перебора" была разработана модель, описывающая соответствующую кривую:

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



Функции


Ниже перечислены основные функции 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 в качестве одной из опций. Ведь серьезные вещи считаются и визуализируются, как правило, под Unix/IRIX/Linux/FreeBSD, и в то же время было бы неправильно игнорировать пользователей Windows. Так что OpenGL как раз и является тем универсальным языком и общим знаменателем, позволяющим вашим приложениям свободно мигрировать с одной платформы на другую.
программы.

OpenGL и Delphi на практике


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

Для начала придется проделать подготовительную работу: настроить формат пикселей с учетом отображаемой информации; создать контекст OpenGL и подготовить сам движок OpenGL к работе.

Формат пикселей удобно вынести в отдельную процедуру, которую мы оформим следующим образом: procedure SetDCPixelFormat (dc: HDC); var pfd: TPixelFormatDescriptor; nPixelFormat: Integer; begin FillChar (pfd, SizeOf (pfd),0); with pfd do begin nSize:= sizeof (pfd); nVersion:= 1; dwFlags:= PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType:= PFD_TYPE_RGBA; cColorBits:= 16; cDepthBits:= 64; iLayerType:= PFD_MAIN_PLANE; end; nPixelFormat:=ChoosePixelFormat (DC,@pfd); SetPixelFormat (DC, nPixelFormat,@pfd); end;

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

Далее посредством вызова ChoosePixelFormat система выбирает подходящий формат пикселя - и мы присваиваем его (через SetPixelFormat) нашему окну.

Теперь нужно инициализировать контекст самого OpenGL посредством функций, содержащихся в модуле Windows, и произвести дополнительную настройку движка: procedure TForm1.FormCreate (Sender: TObject); begin H:=Handle; DC:=GetDC (H); SetDCPixelFormat (DC); RC:=wglCreateContext (DC); wglMakeCurrent (DC, RC); glClearColor (0.6,0.6,0.6,1.0); glMatrixMode (GL_PROJECTION); glLoadIdentity; glFrustum (-1,1,-1,1,2,20); glMatrixMode (GL_MODELVIEW); glLoadIdentity; glTranslatef (0.0,-1.0,-6.0); BeginPaint; end;

Как видим, сначала мы задали для нашей графики необходимый формат пикселей. Теперь при помощи функции wglCreateContext создаем OpenGL-контекст, а впоследствии делаем его текущим контекстом. Далее, используя уже универсальные функции**, произведем настройку "мира", который будем создавать. Для этого через glClearColor очистим контекст и заполним ее 60-процентным черным цветом. Далее выберем матрицу проекций, которая определяет, как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты) и через glLoadIdentity установим единичную матрицу и зададим границы плана в "мировых координатах" при помощи вызова glFrustum. После чего загрузим модельно видовую матрицу и произведем ее смещение (glTranslatef).



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 являются ортогональными, то есть независимыми. Вы можете использовать их в произвольной комбинации, например использование мэппинга не ограничивает возможностей применения светотени. Полнота. Насколько это представляется возможным, OpenGL соответствует набору функций, предоставляемому современными аппаратными средствами графической акселерации. OpenGL старается избегать всего, что должно быть реализовано программно. С другой стороны, по крайней мере, гарантируется получение рабочей картинки, даже если производительность и не позволяет получить ее со всеми подробностями. То есть, если что-то работает на одной платформе, то этот же код будет работать и на другой - хотя, возможно, и с другим результатом. Интероперабельность. В сетевом окружении важно передавать данные между разными платформами. Поэтому OpenGL заранее ориентирован на работу в режиме клиент-сервер, даже если и клиент и сервер расположены на одном компьютере. Расширяемость. Поскольку OpenGL рассчитан на максимальное соответствие возможностям аппаратуры (а аппаратура, как известно, имеет тенденцию развиваться), то в OpenGL также встроены механизмы включения новых функций. С другой стороны, нестабильный интерфейс затрудняет жизнь разработчиков, поэтому новые возможности накапливаются достаточное время и применяются согласованно с выходом новой версии.



Прорисовка сцены


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

Далее в FormPaint используем подготовленные заранее методы DrawFace и DrawElement (см. листинг ниже) для отрисовки упомянутого объекта. А для придания ему еще большей "жары" используем возможности OpenGL по освещению сцены.



Ресурсы


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

Вторая книга (а возможно, по порядку прочтения и первая) - это OpenGL Programming Guide, так называемая .

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