Архивы: по дате | по разделам | по авторам

Прикладная теория Принцев и Нищих...

Архив
автор : Александр Медведев   20.10.1998

Былое поверье

На вопрос, поддерживает ли мой ускоритель OpenGL, я не задумываясь отвечаю "да". Хотя это и неверно - OpenGL поддерживают драйверы моего ускорителя. А если еще точнее, то в их число входит OpenGL - библиотека, способная использовать аппаратные возможности моего ускорителя. На вопрос, поддерживает ли мой ускоритель DirectX, я не задумываясь отвечаю "да". Но на сей раз я абсолютно прав. Запутались в этой демагогии? Я попробую объяснить...

Что нам стоит дом построить

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

 

Стадии конвейера построения изображений

  1. Определение состояния объектов (situation modeling). Эта часть программы не имеет прямого отношения к компьютерной графике, она моделирует тот мир, который будет отображаться в дальнейшем. Например, в случае "Quake" это правила игры и физические законы перемещения игрока, искусственный интеллект монстров и т. д.
  2. Определение соответствующих текущему состоянию геометрических моделей (geometry generation). Эта часть конвейера создает геометрическое представление текущей ситуации нашего маленького "виртуального мира".
  3. Разбиение геометрических моделей на примитивы (tessellation) - первый действительно зависимый от "железа" этап. Здесь на основе информации, полученной на предыдущем шаге конвейера, создается внешний вид объектов в виде набора определенных примитивов. Наиболее распространенный примитив - треугольник, и главным образом с треугольниками работают современные программы и ускорители.
  4. Привязка атрибутов (текстур, освещения и т. д.; attribute definition). На этой стадии определяется, как будут освещены геометрические примитивы (треугольники), а также какие и каким образом на них в дальнейшем будут наложены текстуры (1) . Как правило, на этом этапе информация вычисляется только для вершин примитива.
  5. Видовые геометрические преобразования (projection). Здесь определяются новые координаты для всех вершин примитивов исходя из положения наблюдателя и направления его взгляда. Сцена как бы проецируется на поверхность монитора, превращаясь в двухмерную, хотя информация о расстоянии от наблюдателя до вершин сохраняется для последующей обработки.
  6. Отбрасывание невидимых примитивов (culling). На этой стадии из списка примитивов исключаются полностью невидимые (оставшиеся позади или сбоку от зоны видимости, иногда повернутые обратной гранью) примитивы.
  7. Установка примитивов (setup (2)). Здесь информация о примитивах (координаты вершин, наложение текстур, освещение и т. д.) преобразуется в вид, пригодный для следующей стадии (например, в целые числа фиксированной длины, с которыми работает ускоритель; это могут быть координаты точек буфера экрана или текстур).
  8. Закраска примитивов (fill) - этап собственно построения в буфере кадра (памяти, отведенной под результирующее изображение) картинки на основе информации о примитивах, сформированной на предыдущей стадии конвейера, и прочих данных (таких как текстуры, таблицы тумана и прозрачности и пр.). Как правило, на этой стадии для каждой точки закрашиваемого примитива определяется ее видимость, например, с помощью буфера глубин (Z-буфера), и, если она не заслонена более близкой к наблюдателю и непрозрачной точкой другого примитива, вычисляется ее цвет - на основе информации об освещении и наложении текстур, определенной ранее для вершин данного примитива.
  9. Финальная обработка (post processing) - обработка результирующей картинки как единого целого какими-либо двухмерными эффектами. Это может быть, например, наложение заранее просчитанных изображений, эффект крови в глазах, эффект воды, полноэкранное сглаживание и т. д. Монстры в "Unreal", кстати, даже при наличии ускорителя рассчитываются программно и накладываются после расчета сцены как двухмерное изображение, но с учетом содержимого Z-буфера.

 


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

2 Setup engine - часть ускорителя, которая производит действия по установке примитивов. Setup - сами действия, могут выполняться программой или библиотекой.

Итак, вооружившись теорией, попробуем разобраться, как все обстоит на самом деле.

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

Построили, поделим

Рис. 1. Стадии конвейера и соответствующие программные интерфейсы.

Итак, последовательность действий обозначена. Но кто ее будет выполнять? Есть три основных кандидата на работу - сама программа (как правило - начальные стадии конвейера), библиотека прикладного программирования (интерфейс, API) и ускоритель (см. рис. 1). Впрочем, программы, не использующие ускоритель ("Doom", "Quake" в программном режиме и т. д.), все стадии конвейера выполняют самостоятельно. Программ и ускорителей существует великое множество, а вот число общепризнанных библиотек весьма ограниченно. Наиболее часто компьютерные игры используют следующие библиотеки:

OpenGL - несомненно, принц; первоначально - библиотека для профессиональных графических станций и программ трехмерного моделирования. Она была создана как открытый стандарт в 1993 году на основе собственной библиотеки компании Silicon Graphics, называвшейся IRIS Graphics Library (IRIS GL) и разработанной специально для мощных графических станций. Позже OpenGL была перенесена на многие аппаратные платформы, работающие преимущественно под разновидностями операционной системы Unix. Постепенно она распространилась и на персональные компьютеры - в основном благодаря стремительному росту их производительности и числа ориентированных на нее приложений и игр.

OpenGL берет на себя все действия начиная с 4-го этапа описанного выше конвейера, в том числе выполнение всех видовых преобразований. Хороший пример полезности такого подхода - возможность выпустить версию OpenGL, значительно ускоряющую прорисовку игр (конкретно - геометрические преобразования) на новых процессорах с архитектурой SIMD (Single Instructions/Multiple Data stream) - AMD 3DNow! и Intel Katmai New Instructions (MMX2). В частности, уже существует сокращенная версия opengl32.dll со встроенной поддержкой 3DNow! для "Quake" и "Quake 2". С ее помощью можно получить двукратный прирост числа кадров в секунду на компьютерах c процессором AMD K6-2, что сравнимо с производительностью системы на Pentium II 400 МГц (разумеется, лишь по этому показателю).

Достоинство OpenGL - переносимость программ на другие (не PC+Win32) платформы. Очевидный, но быстро исправляемый недостаток - отсутствие полного варианта библиотеки для некоторых распространенных ускорителей. OpenGL является "чистым" API, то есть проверяет все данные, которые ей передает программа, на корректность, благодаря чему (хотя и ценою уменьшения производительности) достигается высокая стабильность работы. Библиотека интенсивно использует арифметику с плавающей точкой - не только координаты, но и информация о цвете и прозрачности может быть передана в формате с плавающей точкой. Для преобразования координат используются матрицы 4х4, каждая вершина требует от сопроцессора 16 умножений и 12 сложений.

По своей сути OpenGL очень удобна для программистов, но не подходит для создания игр - она слишком медлительна для реализации свойственной играм быстрой и оригинальной 3D-графики, тем более с какими-либо нестандартными эффектами. Вотчина этой библиотеки - 3D-моделирование и дизайн, CAD, студии виртуальных эффектов, хорошо известные Softimage 3D, 3D Studio MAX и другие серьезные программы. Здесь ей пока нет равных, особенно если учесть число разнообразных аппаратных платформ и операционных систем, для которых уже существуют реализации OpenGL (в отличие от Direct3D, привязанной к Wintel-рамкам). Тем не менее, она широко применяется и в современных играх - главным образом ввиду отсутствия достойной замены.

Существует две реализации OpenGL для Windows (точнее - для Win32 API) - Microsoft OpenGL (соответствует стандарту OpenGL 1.1, файл opengl32.dll) и SGI OpenGL (версии 1.1 и 1.2, файл opengl.dll). Причем вариант от Microsoft более распространен - благодаря поддержке MCD (mini client driver - мини-драйвер для ускоряющего работу OpenGL оборудования; ускоряются только основные функции закраски - как следствие, низкая производительность, но драйвер прост в реализации) и ICD (installable client driver - полный OpenGL-драйвер; все функции OpenGL перекладываются библиотекой на драйвер ускорителя; по сути, это полная библиотека, но, как правило, с другим именем файла). OpenGL компании SGI соответствует более поздней версии спецификации OpenGL (1.2), обеспечивает лучшее качество и скорость графики в полностью программном режиме и может использовать MMX-процессоры, но не работает с ускорителями. Microsoft OpenGL входит в поставку Windows NT/98/95 OSR2, (для оригинальной Windows 95 его нужно скачать с сайта корпорации Microsoft).

Создание ICD-драйвера - процесс крайне трудоемкий. Около двухсот функций, тесно взаимосвязанных и имеющих множество параметров, делают библиотеку легкой в использовании, но сложной в разработке. В результате многие графические ускорители (например, все чипсеты компании 3Dfx Interactive) до сих пор не имеют полного и стабильно работающего ICD-драйвера.

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

Direct3D - ранее нищий, с приходом версии 6 - нувориш. Эта библиотека является частью Microsoft DirectX и поддерживается сейчас практически всеми ускорителями. Фактически она представляет собой две библиотеки - низкоуровневую, так называемый Retained Mode (действия начиная с 7-й стадии конвейера), и высокоуровневую - Immediate Mode (с 5-й стадии).

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

Впрочем, получаемые преимущества вполне стоят потраченного времени. Версии игр, поддерживающие Direct3D 6, работают на широком ряде ускорителей, быстрее и с более предсказуемым результатом, чем OpenGL-варианты. Секрет одинакового результата на разных ускорителях прост: в отличие от OpenGL ICD, библиотека - одна для всех ускорителей, а число функций, реализуемых драйвером, значительно меньше, чем у ICD, и они более примитивны. К тому же драйвер, как правило, сертифицируется корпорацией Microsoft, то есть тестируется на корректность реализации всех функций. Уже сейчас Direct3D поддерживает технологии 3DNow! и Katmai New Instructions, довольно новые для графических ускорителей технологии наложения рельефа (bump mapping) и сжатия текстур (texture compression), а также мультитекстурирование (multitexturing), имеет оптимизированные под различные процессоры модули расчета геометрии и освещения, выбираемые исходя из текущей конфигурации компьютера. Ну, и никакого многообразия расширений - любые функции являются частью стандарта и обязаны работать в соответствии с описанием (впрочем, вызывает опасение привычка Microsoft добавлять в каждой версии новые и "по-новому" извлекаемые возможности, из-за чего программы требуют существенной переделки).

Вернусь к вопросу "поддерживает ли мой ускоритель Direct3D..." Дело тут в том, что некоторые ускорители аппаратно поддерживают принятые в Direct3D структуры данных, описывающих параметры треугольников (то есть драйвер моментально передает ускорителю ссылку на список подлежащих прорисовке треугольников, не производя никаких преобразований данных и тем самым резко увеличивая эффективность работы Direct3D); например, у акселератора Riva 128 практически все внутренние структуры данных соответствуют Direct3D версии 3. В соответствии с принятой в Microsoft политикой эти структуры становятся сложнее с каждой версией Direct3D. Однако цикл разработки ускорителя заметно превышает оный для очередной версии библиотеки. Поэтому ни один ускоритель сейчас не поддерживает аппаратно все функции Direct3D (хотя новые чипы и совместимы с наиболее простыми и популярными структурами данных, принятыми в библиотеке).

Fahrenheit - очень интересный совместный проект компаний Microsoft и SGI. Его основная цель - объединение OpenGL и Direct3D плюс создание абсолютно новой технологии (первоначально разработанной компанией Hewlett-Packard), направленной на обработку геометрической информации scene-graph API. В рамках Fahrenheit будет обеспечена совместимость как с OpenGL-, так и с Direct3D- и DirectDraw-программами; более того, все OpenGL-совместимые функции будут ускоряться с помощью драйвера Direct3D, что должно значительно упростить разработку 3D-ускорителей. Кроме того, будут добавлены новые функции, ориентированные на упрощение программирования нового API. Новая технология геометрической обработки переложит на плечи Fahrenheit не только расчет сложных иерархических сцен, но и задачи, подобные адаптивному разбиению на примитивы и привязке атрибутов, то есть станет возможным аппаратное ускорение всех стадий конвейера, начиная с третьей (это занимает сейчас около 90 процентов процессорного времени). Предполагается, что первая версия Fahrenheit появится в конце 1999-го - начале 2000 года.

Ускоритель, говорите?

Итак, в общем случае ускоритель (см. рис. 2) состоит из геометрического процессора (geometry processor, пока практически везде отсутствует), механизма установки (setup engine, стадия 7-я конвейера) и механизма прорисовки примитивов - закраски (fill engine), который при детальном рассмотрении представляет собой комбинацию двух блоков - обработки текстур (texel engine) и обработки буфера кадра (pixel engine).

Рис. 2. Обобщенная блок-схема ускорителя.

Производительность ускорителя зависит от процессора, пропускной способности памяти, шины и самих обрабатывающих блоков. Как правило, приводятся две характеристики - максимальная пропускная способность (треугольников в секунду, triangle throughput) и максимальная производительность закраски (точек в секунду, fill rate). Такой подход возможен, но не очень корректен. Да и все мы знаем, что лучшим тестом является скорость игры, в которую мы играем (fps, frames per second - кадров в секунду на каком-либо стандартном наборе действий), и качество изображения (вот это в цифрах не измерить). Именно эти параметры и необходимо узнать в первую очередь, в Internet или у соседа по подъезду, но не стоит при этом забывать о сильной зависимости числа кадров от объема оперативной памяти и мощности центрального процессора.

Рис. 3. Билинейная фильтрация (стрелками показаны направления интерполяции значений цвета).

Если не вдаваться в технические подробности, закраска происходит следующим образом: блок обработки буфера кадра определяет, видна ли закрашиваемая точка, - например, с помощью буфера глубин (Z-buffer). Если она видна, блок обработки текстур вычисляет цвет текстуры, соответствующий этой точке примитива. На этом этапе очень важны интерполяция (filtering; обеспечивает прорисовку изображения без резких прямоугольных пикселов, даже когда вы находитесь вблизи предмета и разрешение текстуры явно недостаточно) и выбор уровня текстуры (mip-mapping; чтобы устранить искажения, возникающие при чрезмерном удалении от текстуры, выбирается аналог текстуры с меньшим разрешением). Существует несколько методов комбинирования этих операций. Наиболее распространены билинейная фильтрация (bilinear filtering; см. рис. 3: вначале определяется необходимая для данного расстояния текстура, более или менее грубая, а затем значение цвета линейно интерполируется между четырьмя соседними точками текстуры, по каждой из координат) и трилинейная фильтрация (trilinear filtering; см. рис. 4: проводится билинейная фильтрация для двух текстур, более грубой и менее грубой, затем результат интерполируется между ними в зависимости от расстояния между наблюдателем и точкой). Последняя дает лучший эффект, но на современных ускорителях не реализуется за один такт и вдвое снижает скорость закраски. Новейшие ускорители реализуют анизотропную фильтрацию (anisotropic filtering), которая дает прекрасное качество картинки, но занимает еще вдвое больше времени.

Рис. 4. Трилинейная фильтрация (для каждого mip-уровня билинейная, затем интерполяция между ними в зависимости от расстояния).

Вычисленный с помощью одного из описанных выше методов цвет текстуры помещается в буфер кадра. Он заменяет находившееся там ранее значение либо комбинируется с ним по какому-либо правилу (combination, blending, alpha-blending), что позволяет реализовать цветное освещение, эффекты типа металла или отражения, трилинейную фильтрацию, если она не поддерживается аппаратно, и т. д. (так называемое многопроходное построение изображения, multipass rendering). Как правило, для каждой точки текстуры кроме RGB-цвета можно задать степень ее прозрачности (alpha, RGBA-формат текстуры), которая будет использоваться ускорителем для регулирования степени воздействия источника на приемник. Подобным образом закрашиваются, например, полупрозрачные по краям взрывы и ореолы вокруг источников света в "Unreal".

Не является жизненно необходимым, но очень ускоряет работу программ, использующих многопроходное построение изображения (например, "Quake 2" или "Unreal"), мультитекстурирование: фактически два блока обработки текстур одновременно вычисляют два цвета по двум текстурам для одной точки примитива, а затем комбинируют их между собой. Важны также точность представления цветов: 16 бит - Hi-Color или 32 бита - TrueColor (последний гораздо лучше), и точность буфера глубин (Z-buffer, 16 бит хуже, 24 и 32 - лучше), используемого для определения видимости отдельных точек примитива. Ошибки в определении глубины способны приводить к странным эффектам.

И последнее - наложение глобальных эффектов на готовую картинку: например, тумана, дымки или темноты (с точки зрения реализации - одно и то же) - эффект известный как fogging. Кроме того, применяется метод полноэкранного сглаживания (full screen antialiasing): изображение рассчитывается с большим разрешением, соседние точки изображения усредняются, и результат выводится на монитор. Подобным образом устраняются резкие границы между многоугольниками (polygons), изображению придается приятный "монолитный" вид. Распространено также краевое сглаживание примитивов (edge antialiasing), приводящее к подобному, чуть худшему результату, но и требующее гораздо меньше затрат на построение изображения.

Вот так...

А технологии тем временем идут вперед... Но давайте лучше оглянемся назад, памятуя все же, что новое - это лишь хорошо забытое старое. Около десяти лет назад, когда речь о качественной 3D-графике реального времени еще не шла, бурно развивались алгоритмы создания реалистичных 3D-изображений, рассчитанные на многочасовой программный расчет (подобные алгоритмы лежат в основе современной 3D-анимации и спецэффектов, используемых в кино). Такие новые для игровых ускорителей и программ возможности, как наложение рельефа, отражение, сплайны, адаптивная детализация, блики и ореолы, и другие алгоритмы были придуманы и реализованы уже много лет назад, пусть и не в реальном времени. И нетрудно предсказать, чего достигнут завтрашние ускорители и игры. Это, например, более сложная, чем закраска Гуро, закраска Фонга - когда освещение вычисляется исходя из направления нормали для каждой точки треугольника, а не только для его вершин (как следствие, отпадет необходимость в картах освещения, широко используемых в современных играх). Далее, в 3D-картах появятся не только геометрические ускорители, но и аппаратные тесселяторы (устройства, осуществляющие 3, 5 и 6-ю ступени конвейера). Станет возможным ускорение систем частиц и воксельных (поточечных) методов 3D-графики. А затем следует ожидать сплайновых поверхностей и зачатков трассировки лучей аппаратными средствами.

Хвосты

© ООО "Компьютерра-Онлайн", 1997-2021
При цитировании и использовании любых материалов ссылка на "Компьютерру" обязательна.