четверг, 3 ноября 2011 г.

Что внутри. VBO, часть вторая, реализация

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


Как уже было сказано ранее - основное преимущество перед glBegin/glEnd и VBA заключалось в хранении данных в видеопамяти, что позволяло GPU мгновенно получать доступ к данным, не дожидаясь пока CPU доставит их по достаточно медленной шине и простоев, связанных с таким ожиданием. Но аналогичный результат можно было получить и через дисплейные списки, суть которых как раз и была в том, чтоб набор команд ОГЛ, в том числе и команд рисования, скомпилировать в один пакет, загрузить его в видеопамять и там выполнить эти же инструкции. Мало того, в дисплейный список можно было помещать не только команды рисования, но и команды установки состояний ОГЛ, таких как бинд текстур, установка свойств материалов, задание трансформаций и т.д. (мы к этому еще вернемся, когда будем рассматривать проблемы создания GUI). Кроме этого, в дисплейном списке выполнялось еще много чудесных вещей, таких как оптимизация геометрии под pre-/post-T&L cache. В результате чего многие тесты производительности VBO в сравнении с DL с треском проваливались. О pre-/post-T&L cache мы поговорим позже, сейчас мы рассмотрим ключевые моменты, почему все же стоит использовать VBO, не смотря на все описанные ранее проблемы.

Первая ключевая особенность это возможность менять часть (или все) данных прямо в видеопамяти. Представь что вы сделали классический пример со снеговиком, скомпилировали его в дисплейный список, а теперь вам вдруг понадобилось приподнять ему нос, для этого нужно всего-то передвинуть одну-единственную вершину, но используя дисплейный списки мы были вынуждены из-за одной вершины полностью перекомпилировать весь дисплейный список со всей геометрией и всеми командами. А теперь представьте себе что мы хотим чтоб он постоянно двигал носом, что в этом случае делать? В таких случаях мы, скрипя зубами, разбивали модельку на несколько частей, одну часть запихивали в дисплейный список, вторую, которую нужно было обновлять, помещали в буфер VBA, обновляемый на каждом кадре, или вообще рисовали через glBegin/glEnd. Сделали? Молодцы, а теперь нам нужно поморгать глазками....

В результате для динамически изменяемых моделей использование дисплейного списка было неприменимо, и вместо него приходилось использовать те самые glBegin/glEnd, или более новый (но так же нагружающий шину) VBA. Вот тут-то VBO раскрывается во всей красе, имея доступ ко всем вершинам модели мы можем изменить любую из них, что происходит практически мгновенно. В худшем случае скорость обновления приближается к скорости работы VBA.

Естественно, обойти стороной такую возможность я не мог, потому в VBOMesh вы можете манипулировать с данными на низком уровне, обновляя как отдельные вершины так и полностью перестраивая буфер VBO. Так же эта возможность используется разными частями модуля, к примеру при выводе системы частиц или GUI. Более подробно об этом будет сказано при рассмотрении соответствующего функционала.

Второй важный момент - раздельные буферы вершинных атрибутов. Это фактически не имело аналогов (кроме VBA). Идея заключается в том, что мы можем хранить в видеопамяти несколько наборов данных, к примеру два набора текстурных координат или несколько наборов буферов цвета, или несколько наборов вершинных координат. Тогда для того, чтоб "переодеть" актера достаточно подключить второй текстурный буфер, что заключается в изменении всего одного индекса. Чтоб перекрасить автомобиль - достаточно так же поменять один индекс, чтоб заставить снеговика повернуть голову - так же нужно поменять один индекс. Таким образом можно реализовать морфинг, можно реализовать смену "одежки" или раскраску юнитов, можно реализовать разные состояния GUI, сделать развивающийся плащ или флаг и многое другое. Все это выполняется мгновенно, так как все данные уже находятся в видеопамяти и за счет разделения этих буферов между несколькими объектами существенно экономится память.

В отличии от GLScene в моем модуле все идентификаторы буферов VBO доступны для чтения/записи. Это конечно перекладывает ответственность за корректность идентификаторов буферов на пользователя, но открывает перед пользователем новые перспективы.

Третий важный момент - возможность представления геометрии в виде текстуры и наоборот.
Существует так называемая технология "r2vb" (render to vertex buffer), включающая в себя технологии VBO + PBO + FBO + MRT. Идея заключается в том, что используя PBO (Pixel Buffer Object) можно представить буфер VBO в виде текстуры (и как следствие - можно использовать его в фрагментном шейдере) и наоборот, используя FBO можно прямо в фрагментном шейдере сгенерировать буфер VBO.

Примером такого использования может быть "аппаратная тесселяция", нет, не та, для которой нужно иметь современную видеокарту. Это полноценная аппаратная тесселяция (так как геометрия формируется на GPU в фрагментном шейдере), но работающая на всех видеокартах с поддержкой ОГЛ 1.5+

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

Все описанные технологии представлены в движке, боле подробно в последующих сообщениях.

В следующей части я рассмотрю вопросы оптимизации VBO.

3 комментария:

  1. А есть exe этой самой хардварной тесселяции на огл1.5+?

    ОтветитьУдалить
  2. Держи:
    http://file.qip.ru/file/Rqcv0oOQ/R2VBDemo.html
    Демка правда старенькая, там просто адаптация моей демки к статье по FBO, сейчас это же можно сделать немного проще, но идею аппаратной тесселяции показывает.

    ОтветитьУдалить