пятница, 4 сентября 2009 г.

How antialiasing works. Part 1.

Недавно я осознал, что мои познания в области антиалиаcинга на современных GPU - весьма посредственные. Учитывая, что появляются новые его разновидности, а также то, что теперь можно делать deferred rendering и HDR rendering с включенными антиалиасингом, необходимо разобраться в предмете более подробно. Т. к. тема обширная, разбираться буду постепенно и разобью обзор на несколько частей.

Для начала: cуществует несколько видов антиалиасинга. Простейший из них - это суперсэмплинг (аббревиатура SSAA или FSAA - Full-Scene Anti-Aliasing). Такой вариант антиалиасинга поддерживался, например, в NV10. Суперсэмплинг не требует специальной аппаратной поддержки и реализуется очень просто: сцена рисуется в буфер бОльшего разрешения, а потом сжимается с фильтрацией в меньшее разрешение. Фильтрация осуществляется путём простого усреднения цветов соседних пикселей. Например, если ваше конечное разрешение - 1024х768, то при 4x суперсэмплинге FSAA буфер должен иметь разрешение 2048х1536. Понятно, что этот способ очень сильно нагружает филлрейт - производительность падает примерно пропорционально увеличению разрешения, т. к. расчёт цвета и выборка из текстуры делается для каждого субпикселя. Такое падение производительности происходило на упомянутом GeForce 2. Впрочем, у этого метода есть одно преимущество - он способен сглаживать изображение, которое не было нарисовано с помощью треугольников (а, например, рассчитано в фрагментном шейдере).

Другой, более продвинутый вариант антиалисинга - это мультисэмплинг (MSAA - Multi-Sample Anti-Aliasing). Если копнуть в прошлое, то можно найти расширение OpenGL GL_SGIS_multisample от 1994 года - уже тогда на рабочих станциях SGI была его разновидность. На consumer hardware мультисэмплинг появился впервые, видимо, на видеокартах 3dfx (серия Voodoo 5), для этих видеокарт существовало ограниченное расширение GL_3DFX_multisample. NVIDIA впервые реализовала поддержку этого вида антиалиасинга в NV20 (GeForce 3). С тех пор MSAA с теми или иными вариациями реализуется на всех поколениях графического железа.

При мультисэмплинге фрагмент изображения перестаёт быть своего рода "атомом" (др.-греч. ἄτομος — неделимый). У него появляется внутренняя, невидимая до поры до времени структура - отдельные сэмплы (отсчёты). Говоря образно, у фрагмента появляется своё собственное разрешение (пусть и небольшое), и он способен "видеть" растеризуемые примитивы более подробно. Типичное кол-во сэмплов, которые определяют уровень антиалиасинга - 2, 4, 6 и 8.

Теперь разберём техническую сторону вопроса более подробно (я черпал информацию в основном из расширения GL_ARB_multisample и сверял с другими источниками).

Если формат пикселя кадрового буфера поддерживает мультисэмплинг, то к кадровому буферу добавляется специальный буфер отсчётов (multisample buffer). Такие значения сэмплов фрагмента, как цвет, глубина и значение трафарета сохраняются в этом буфере. Также с каждым фрагментом изображения связывается так называемое значение охвата (coverage value), кол-во бит в котором равно кол-ву сэмплов на фрагмент. Т. е. для каждого сэмпла отводится один бит из значения охвата. Эти дополнительные данные нужны для того, чтобы понять, какая площадь фрагмента перекрывается треугольником.

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

Если в процессе растеризации сэмпл (как идеальная точка) попадает внутрь растеризуемого примитива или оказывается на его границе, то бит в значении охвата для этого сэмпла устанавливается в 1, иначе в 0. Тесты глубины и трафарета, а также смешивание (blending) цветов выполняются на уровне отдельных сэмплов, а не на уровне фрагмента. Кроме того, они выполняются только для тех сэмплов, для которых бит в значении охвата установлен в 1, иначе все операции для этого сэмпла пропускаются. Если тест трафарета или тест глубины проваливается, прекращается дальнейшая обработка только данного сэмпла, а не всего фрагмента. Фрагментный шейдер (или простая выборка из текстуры в случае FFP на NV20/25) всегда выполяется на уровне фрагмента, и все сэмплы получают одинаковое значение цвета, но значение глубины генерируется растеризатором для каждого сэмпла отдельно. (TODO: неясно, что происходит со значением глубины, если оно модифицируется в шейдере?). Согласно спецификации, значение трафарета генерируется для всего фрагмента, а не для каждого сэмпла отдельно:
The single fragment color value is used for all sample operations, however, as is the current stencil value.

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

Как видно, основным преимуществом MSAA метода перед FSAA является меньшее кол-во текстурных выборок и вызовов фрагментного шейдера, хотя требования к памяти и framebuffer bandwidth остаются неизменными. Здесь появляется некоторая свобода, т. к. одно и тоже значение цвета для нескольких сэмплов позволяет задействовать цветовую компрессию:
If the color samples in the multisample buffer store fewer bits than are stored in the color buffers (...) presumably a compression scheme is being employed, and is expected to maintain an aggregate resolution equal to that of the color buffers.

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

Комментариев нет:

Отправить комментарий