| Рис. 5 ...потом создаем карту освещенности для нужного источника света...
|
| Растеризация. Последний этап конвейера называется растеризацией. Это единственный этап конвейера, который даже в старых акселераторах выполнялся на аппаратном уровне. Наиболее сложный этап растеризации — удаление скрытых поверхностей (HSR — Hidden Surface Removal). О нем давайте поговорим подробнее.
Просчет сцены со всеми объектами (видимыми и невидимыми) способен посадить на мель любую современную видеокарту. Поэтому применяется следующий метод. Определяются полигоны, которые гарантированно не попадут в кадр. Эти полигоны отсекаются. И рендерится только та часть сцены, которую в данный момент “видит” виртуальная камера. Такой подход экономит системные ресурсы. Все было бы хорошо, если бы не одно
| Рис. 6. ...и получаем световое пятно от фонаря на стене.
|
| “но”. Отсечь невидимые поверхности — задача нетривиальная. Как учитывать полигоны, у которых “в кадре” оказывается только кусочек? А как учесть полигон, который находится где-то там за стенкой и все равно не виден, а нам придется его зачем-то просчитывать?
В разные времена проблему отсечения невидимых поверхностей решали по-разному. Но начало всегда было одинаковым. Шестью плоскостями по трем координатам ограничивается область сцены, которая гарантированно будет видна на экране. Эти плоскости образуют объем отсечения (clipping volume), который берется с некоторым запасом. Затем в дело вступает backface culling — отбрасывание задних граней. У каждого полигона помимо координат вершин есть важнейшая характеристика — нормаль. Это вектор, который лежит на перпендикуляре, восставленном из геометрического центра треугольника. С помощью специальной функции можно по координатам вершин треугольника определить его нормаль.
У каждого полигона есть две стороны — лицевая и обратная. Нормаль определяет, куда “смотрит” полигон. Представьте себе сферу. Нормали сферы направлены во внешнюю сторону, и ее поверхность образована лицевыми сторонами граней. Примерно половина полигонов сферы “смотрит” от экрана, вторая половина — на экран. А это значит, что все полигоны, смотрящие от экрана, гарантированно не видны. Их можно отсечь. И рендерить акселератору придется только половину полигонов сферы. Конечно, не все трехмерные объекты такие симметричные, как сфера, но у большинства примерно половина полигонов не видна. На этом принципе основывается backface culling.
|
|
| Рис. 7. Динамическое освещение — альтернативный картам освещенности способ создания реалистичного освещения. Выглядит он куда эффектней, но не каждый акселератор потянет такую красоту.
|
| В зоне отсечения все еще много полигонов. И большая их часть не видна. Это —объекты за стенами, под полами, над потолками. Обычными способами отсечь их невозможно. Простой расчет, что находится перед стенкой, а что — за ней, занял бы массу процессорного времени. А ведь есть еще
| Рис. 8. Типовое BSP-дерево малополигональной модели.
|
| и окна, а то и полупрозрачные панели. Считать до скончания веков. Разработчики графических движков и “железа” пытались придумать самый рациональный путь решения этой проблемы. И придумали несколько методов, таких как BSP-деревья и метод порталов. Подробно на этих методах останавливаться не будем.
| Рис. 9. Другой способ отсечь невидимые объекты — разделить сцену плоскостями на логические зоны.
|
| Итак, различными способами сцена освобождается от лишних полигонов.
| Рис. 10. Для такой плотной застройки высокополигональных зданий из Half-Life 2 тяжело задать логические зоны, но еще тяжелее построить BSP- дерево. Поэтому иногда программисты пользуются гибридными методами.
|
| Но проблемы на этом не заканчиваются. Ведь остались еще перекрывающиеся полигоны. Их sнадо рендерить в строгом порядке. Те, что дальше — рендерятся раньше. Те, что ближе — позже.
Это еще не все. Бывает, что два полигона пересекаются в некоторой точке. Кого из них рендерить первым? Нам понятно, что надо отрендерить часть первого и часть второго. Но вот процессору это совсем не понятно. Как разобраться с этими трудностями? Есть два общепринятых метода. Первый — Z-буфер. А второй — так называемая Z-сортировка. На Z-сортировке мы подробно останавливаться не будем, так как это довольно грубый и малоэффективный метод.
| Рис. 11. Так задается объем отсечения (clipping volume).
|
| Z-буфер — это специальная область видеопамяти. В Z-буфере хранится значение глубины для каждого пиксела. Когда рендерится новый пиксел треугольника, его глубина сравнивается со значением, которое уже хранится в Z-буфере для точки на экране с такими же координатами X и Y, то есть с соответствующей точкой предыдущего треугольника. Когда новый пиксел “глубже”, чем значение в Z-буфере, пиксел не виден. Если значение его глубины меньше значения в Z-буфере, пиксел виден, и значение его глубины записывается в Z-буфер. В современных акселераторах часто используется W-буфер, в котором хранятся значения, обратные Z-глубине. W-координаты тем удобны, что без лишних расчетов корректно соотносятся с перспективой, тогда как для Z-координат приходится корректировать результат интерполяции координат вершин треугольников.
| Рис. 12. Две накладывающиеся фигуры до работы Z-буфера...
|
| Некоторые приложения позволяют задать глубину или разрядность Z-буфера. Чем выше разрешающая способность, тем точнее рендерятся полигоны. Если выбрать буфер с малой разрядностью, может появиться Z-алиасинг (полигоны “проваливаются” друг сквозь друга), потому что порой пикселам двух треугольников будет соответствовать одна и та же Z-координата, а значит — и глубина.
Каждый новый кадр сначала рендерится не на экран, а в специальный буфер в видеопамяти, который называется фрейм-буфером. У фрейм-буфера два слоя (передний и задний). В заднем — новый
| Рис. 13. ... и после.
|
| кадр, а в переднем — кадр текущий. Когда приходит время очередного рендера, содержимое этих слоев меняется местами (swap). В итоге на экране мы видим новый кадр, а старый кадр пересылается в задний буфер, где немедленно затирается очередным свежеотрендеренным. Этот метод получил название двойной буферизации.
|