Новые возможности Титана

В ноябре 2001 года калифорнийская компания nVidia представила на суд общественности свою последнюю (на тот момент) разработку — графический чипсет GeForce 3 Titanium. Данная “железка”, как могло показаться, ничем не отличалась от своего предшественника, кроме тактовых частот шины и самого GPU (как теперь принято называть графический чипсет), однако создатели наделили Titanium двумя новыми возможностями (или, если хотите, функциями). Это буфер теней (shadow buffer) и объемные текстуры (3d textures). На первый взгляд, конечно, данные функции далеко не столь революционны, как, например, шейдеры, однако не стоит спешить с выводами — просто nVidia на сей раз решила не проводить широких рекламных кампаний. А на самом деле данные функции заслуживают весьма пристального внимания, так как действительно могут ощутимо повысить реалистичность трехмерных сцен. Итак, обо всем по порядку.

Начнем, пожалуй, с буфера теней. Само собой, и без аттестата о среднем образовании можно догадаться, что данная функция предназначена для отображения теней. Конечно, у многих может возникнуть вполне естественный вопрос: “Что ж тут такого, ведь в играх, например, тени уже давно стали привычным делом?”. Да, тени в играх все мы видели, и не раз. А дело в том, что в играх тени строятся, к сожалению, с помощью всего лишь двух весьма примитивных искусственных методов.

20080703_ill3.jpg

Первый метод носит название карты освещенности (lighting mapping). Его суть заключается в том, что на все статичные плоскости игрового мира (стены, полы и т.д.) накладываются предварительно рассчитанные специальным образом текстуры (как правило, черно-белые), имитирующие свет и тень. Недостаток такого подхода очевиден — его можно применять только на статичных объектах, так как карты освещенности динамически пересчитываться не могут. Единственным преимуществом этого метода является возможность получения довольно-таки мягких теней с минимальными затратами аппаратных ресурсов.
Второй подход, который носит мудреное название планарные проекции теней (planar shadow projections), куда более динамичен и гибок, нежели предыдущий, но реалистичность картинки, полученной с его помощью, оставляет желать лучшего. Суть метода заключается в том, что каждая вершина объекта, отбрасывающего тень, прое­цируется на близлежащую плоскость, а затем по этим проекциям строится силуэт объекта, который похож (относительно, конечно) на тень. Недостатков, ясное дело, здесь хватает, ведь объекты будут отбрасывать тень не куда угодно (как в “реале”), а только туда, куда укажет программист.

20080703_ill4.jpg

А теперь, разобравшись с “технологиями вчерашнего дня”, можно перейти и к буферу теней. Метод этот, кстати, появился достаточно давно и по сути представляет собой нечто среднее между предыдущими двумя. Однако для того чтобы внятно объяснить вам идею, лежащую в основе буфера теней, мне придется сначала ввести еще одно понятие (многим, надеюсь, знакомое) — z-буфер.
Z-буфер — это метод сортировки точек в зависимости от глубины, то есть по z-координате (отсюда и название). Зачем он нужен? Все дело в том, что в процессе построения трехмерной сцены, после того как все трехмерные объекты были заданы в видовых координатах (координатах экранной плоскости), все, что мы можем — это лишь нарисовать их каркасные модели. А если мы желаем изобразить их таким образом, что бы все полигоны наших объектов были закрашены, да еще и так, чтобы передние плоскости (более близкие к нам) перекрывали задние, а ни в коем случае не наоборот, то будет просто необходимо отсортировать все точки по глубине. Вот здесь-то и пригодится нам метод z-буфера.
Работает он, в двух словах, следующим образом. Для начала в памяти создается двумерный массив, размер которого равен разрешению экрана, а затем значения всех элементов массива заполняются некоторым максимально допустимым числом. Данный процесс заполнения происходит при отрисовке каждого кадра и называется очищением или инициализацией z-буфера. Затем каждая точка каждого полигона проецируется на экранную плоскость, и ее z-значение (глубина) сравнивается с соответствующим по координате значением в z-буфере. Если значение глубины окажется меньше, чем уже находящееся z-буфере, то оно записывается в буфер, иначе проверка идет дальше.
Не сомневаюсь, что многим уже не терпится спросить, чего ради я гружу вас каким-то z-буфером, в то время как речь вроде как должна идти о буфере теней. Спокойствие, только спокойствие. Дело в том, что направленный источник света тоже можно представить как некую плоскость, от которой идет свет (аналог экранной плоскости), на которую будут проецироваться точки всех полигонов. Таким образом, для того, чтобы определить, видна точка источнику света или не видна (проще говоря — освещена или не освещена), мы можем воспользоваться тем же самым z-буфером, только теперь он будет называться буфером теней.

20080703_ill1.jpg

Что же нового внесла nVidia в эту идею? Собственно говоря, ничего, кроме того, что этот алгоритм впервые появился аппаратно реализованным на low-end видеокарте. А реализован буфер теней на Titanium’е по алгоритму, состоящему из следующих фаз:
1) Преобразование пикселя в координатную систему источника света.
2) Использование техники фильтрации текстур для чтения z-значений пикселей, лежащих вокруг проверяемого пикселя. Затем эти данные используются для следующих целей:
а) сравнение z-значений пикселей, лежащих вокруг, с z-значением самого пикселя, чтобы определить, какая часть пикселя находится в тени. С помощью полученных данных создаются плавные переходы теней между ребрами (soft edges for shadows) на ровных объектах, для чего используются 256 значений затенения;
б) затем с помощью алгоритма фильтрации текстур значения цвета этого пикселя и пикселей лежащих рядом интерполируются.
3) Результаты этапов 2а и 2б используются как входные данные для nfiniteFX-движка, предназначенного для выполнения операций пиксельного шейдирования. На этом этапе, собственно, и определяется по вышеописанному алгоритму, где находится пиксель — в тени или на свету, а также накладываются данные от результата операции 2а. Движок nfiniteFX также может и отключить спекулятивные источники света для затененных пикселей, чтобы увеличить реалистичность сцены.
Результат рендеринга с использованием­ буфера теней демонстрируют иллюстрации 1 и 2. На рисунке 1 показано, что объект может отбрасывать тени сам на себя (object self-shadow), а на рисунке 2 — то, что объекты могут быть действительно гладкими (soft edges for shadows).

20080703_ill2.jpg

А теперь пора перейти к объемным текстурам, которые, по сути, являются теми же всем нам знакомыми текстурами, но с добавлением еще одной координаты — глубины. Так что трехмерные текстуры вполне можно было бы назвать псевдовоксельной графикой. Идея, как и буфер теней, не нова (впервые мысль о создании трехмерных текстур появилась на SGI, а аппаратная поддержка — на ATI Radeon), однако, ввиду целого ряда проблем, распространения они до сих пор не получили и, по всей видимости, в ближайшее время не получат. Главными проблемами, встающими перед разработчиками, являются: слишком большой размер трехмерных текстур, проблемы с уровнями детализации и тормознутость вывода. К счастью, часть этих проблем в nVidia все-таки удалось решить.
Итак, первая проблема — это большой размер объемных текстур. Многие, наверное, тут же возмутятся — мол, какой такой большой размер, если нынче на видеокарты памяти ставят едва ли не больше, чем на системную плату! Это конечно так, но в данном случае очень уместна фраза “размер имеет значение”! А насколько большой размер, я сейчас объясню. Например текстура размером 256x256x256 пикселей в 32-битном цвете займет 64 мегабайта, а значит всю память видеокарты. А если взять размерчик 512x512x512, то получится аж все 512 мегабайт(!). Проблему в nVidia удалось частично решить с помощью компрессии трехмерных текстур, причем “Титан” может проводить компрессию как по одному-двум, так и по трем измерениям. К тому же имеется несколько режимов компрессии, например 4:1 и 8:1. Таким образом, текстура с исходным размером 64 мегабайта может быть ужата до 8 мегабайт!
Второй проблемой является то, что трехмерные текстуры плохо выглядят без уровней детализации или, другими словами, мипмэппинга. Суть проблемы легко уяснить, взглянув на рисунок 3 (слева — без мипмэппинга, справа — с ним). Само собой, обычный мипмэппинг с трехмерными текстурами проводить нельзя, т.е. обычная трилинейная фильтрация здесь не пройдет. Эту проблему в nVidia решили довольно хитро — им удалось разработать специальный алгоритм, дословный перевод которого на русский звучит примерно так — “четырехлинейная фильтрация”(quad-linear filtering). С ее помощью трехмерные текстуры становятся ровными в любом направлении.
Третьей проблемой стала медлительность объемных текстур. Разработчики из nVidia решили эту проблему с помощью текстурного кэша, причем вышеописанные трехмерный мипмэппинг и сжатие текстур позволяют использовать кэш весьма эффективно, так как время обмена данными между GPU и памятью сокращается.
Однако технологии технологиями, но пора уже и про применение этих самых технологий поговорить, а именно — о том, какие спецэффекты можно реализовать с помощью трехмерных текстур.
Первый спецэффект — объемный туман. Конечно, все мы видели туман в играх и раньше, да только то была просто последовательность прозрачных спрайтов или плавное обрезание заднего фона (обидно, да?). А здесь туман полностью объемный, поэтому он может изменять свою плотность не только по высоте и длине, но и по глубине (рис. 4).
Второй спецэффект — так называемые импостеры (от английского imposture — обман). Импостеры — это набор двухмерных примитивов, которые словно бы являются ортогональными по отношению к камере, поэтому начинает казаться , что объект имеет весьма сложную геометрию, но на самом деле просто одна двухмерная текстура накладывается на примитив. Разумеется, таким способом отображение сложного объекта (точнее говоря, имитация, или обман, если хотите) намного быстрее, чем если бы объект был полностью трехмерным. Единственная проблема, связанная с импостерами, заключается в том, что они смотрятся нереалистично (еще бы), если объект или источник света, его освещающий, как-либо движется. Хотя в nVidia и не решили эту проблему, но все-таки импостеры в реализации на “Титане” смотрятся намного лучше за счет 3D-мипмэппинга. Кроме того, трехмерные текстуры позволяют принимать импостеру верную ориентацию в зависимости от положения камеры без каких-либо дополнительных вычислений.
Третий спецэффект — улучшение качества изображения. В данном случае под этим термином подразумевается то, что трехмерные текстуры могут хранить не только текстурные данные, но и другие параметры. Например, с их помощью возможно наведение резкости изображения в зависимости от глубины, благодаря тому, что в 3D-текстуре хранится информация, базирую­щаяся на расстоянии от камеры (например, фокусное расстояние, f-стоп и т.д.) С помощью специального математического аппарата, оставляя один из этих параметров неизменным и при этом обрабатывая другой, реализуется данный эффект.
Четвертый спецэффект — процедурные текстуры, с помощью которых можно создавать различные эффекты освещения, например, объемные лучи света, взрывы и эффекты плазмы.
Что ж, буфер теней и трехмерные текстуры несомненно повышают качество изображения и предлагают программистам множество различных приемов и хитростей, но не являются панацеей при создании полностью реалистичных изображений в реальном времени. Например, свет в действительности падает на 1/r2 (где r — расстояние от наблюдателя до источника света) но буфер теней эту проблему не решает, поэтому смотрятся тени на объектах недостаточно естественно. С трехмерными текстурами все тоже не очень-то просто — несмотря на то, что они достаточно неплохо ужимаются, памяти все равно не хватает, ведь при размере одной текстуры в 8 мегабайт можно сохранить в памяти видеокарты только восемь текстур и места больше вообще ни на что не хватит. Однако, несмотря на все это, нововведения nVidia если уж и не революционны, то все равно весьма существенны для развития трехмерной графики реального времени.


Рекомендуем почитать: