Уроки Коммент.

Создание игр » DirectX 9, Featured » Vertex buffer, Index buffer

Vertex buffer, Index buffer

Vertex buffer Index bufferVertex buffer и Index buffer обычно используются для хранения информации о моделях в Direct3D. Соответственно, один из них хранит информацию о вершинах модели, а второй – об индексах, которые определяют из каких именно вертексов будут собираться треугольники модели. Vertex buffer, фактически, может хранить очень много данных – информацию о положении в мире, о нормалях, TBN-пространстве (используется в частности для normal mapping) и много другой информации. Учитывая, что хранить каждый тип информации в vertex buffer можно разными способами – они часто получаются достаточно сложными по формату и методам создания/упаковки данных в них. В то же время Index buffer обычно крайне прост – он просто хранит индексы (номера) вертексов и больше никакой дополнительной информации. Давайте же разберёмся поподробнее в том, зачем нам вообще использовать Vertex buffer’s и Index buffer’s.

Vertex Buffer

Вертексный буфер это буфер, хранящий данные о вертексах. Конкретнее, он может хранить:

  • информацию о позициях (например, позиция vertex’а в мире)
  • информацию о текстурных координатах в данном вертексе
  • информацию о цвете
  • информацию о нормалях к данном вертексу
  • и многое другое

Конкретный список типов данных, которые можно хранить в vertex’е вертексного буфера, Вы можете посмотреть в MSDN, так же, как и информацию о том, каким образом можно использовать эти данные. Немного позже я объясню Вам, как создавать и использовать Vertex Buffer, а так же как правильно указать Direct3D то, данные какого типа и где хранятся в каждом vertex’е этого буфера.

Index Buffer

Индексные буферы используются для задания индексов (номеров) вертексов в модели, из которых графическая карта будет “собирать” треугольники для отрисовки. На картинке справа Вы видите, как это задаётся. У нас есть 4 точки, составляющие квад, который, в свою очередь состоит из 2х треугольников. Из этих 4 точек, 2 штуки общие для обоих треугольников. Соответственно, в индексном буфере мы указываем индексы этих точек для использования как в первом, так и во втором треугольнике. Но что же нам это даёт? А вот что:

  1. Во-первых, мы экономим память на вертексах. Размер индекса либо 2 байта, либо 4, размер вертекса обычно не меньше 16-24 байт, а бывает и больше. Соответственно, в случае того же квада, если бы мы не использовали индексы, то vertex’ы занимали бы 6*24 = 144 байта. С индексами они займут 4*24 (вертексы) + 6*2 (индексы) = 96+12 = 118 байт. Т.е. мы сэкономим около 20% памяти. А для больших и хорошо оптимизированных моделей эта экономия может быть даже больше 50%.
  2. Во-вторых, только индексированные примитивы обрабатываются кэшем видео-карты. А кэш видео-карты позволяет не обрабатывать повторяющиеся вертексы (т.е. вертексы с одинаковыми индексами). Без использования индексов этого не просиходит. Таким образом, мы можем сэкономить ещё какой-то % производительности – обычно он не очень большой, но это вовсе не значит, что он совершенно не заметен: если у вас в кадре будет много “тяжёлых” моделей и в каждой много вертексов – разница может быть очень существенной.

Создание Vertex buffer и Index buffer

Поскольку и Vertex buffer, и Index buffer обычно хранятся непосредственно в памяти видео-карты, для их создания (выделения под них места) и работы с ними, в Direct3D есть отдельные функции:

HRESULT CreateVertexBuffer(
  [in]           UINT Length,
  [in]           DWORD Usage,
  [in]           DWORD FVF,
  [in]           D3DPOOL Pool,
  [out, retval]  IDirect3DVertexBuffer9 **ppVertexBuffer,
  [in]           HANDLE *pSharedHandle
);

Эта функция позволяет создать новый vertex buffer, при этом указывается:

  1. длина создаваемого vertex buffer’а (в байтах!!!)
  2. как мы будем его использовать, обычно = D3DUSAGE_WRITEONLY
  3. формат вертексов в буфере, в последнее время чаще всего ставят =0
  4. Pool, в котором будет создан буфер, обычно это либо D3DPOOL_DEFAULT, либо D3DPOOL_MANAGED
  5. передаётся указатель на указатель (угу, именно так) на вертексный буфер. в этот указатель функция запишет адрес, по которому был создан буфер.
  6. последний параметр не используется и всегда ставится =0
HRESULT CreateIndexBuffer(
  [in]           UINT Length,
  [in]           DWORD Usage,
  [in]           D3DFORMAT Format,
  [in]           D3DPOOL Pool,
  [out, retval]  IDirect3DIndexBuffer9 **ppIndexBuffer,
  [in]           HANDLE *pSharedHandle
);

Создание index buffer аналогично:

  1. Указываем длину буфера (в байтах)
  2. Как будем использовать – аналогично вертексному обычно = D3DUSAGE_WRITEONLY
  3. Форматов бывает всего два: D3DFMT_INDEX16 (16битный индекс, WORD), либо D3DFMT_INDEX32 (32битный индекс, DWORD)
  4. Указатель, по которому запишется адрес созданного буфера
  5. Ноль, не используется

Выводы

Выводы из всего этого очень просты: по возможности, всегда используйте index & vertex buffer’ы, т.к. это не только сократит количество памяти, используемой моделью, но и повысит быстродействие вашей программы. При этом, хочу заменить, что я лично использую их далеко не всегда – часто бывает ситуация, когда на экране надо нарисовать буквально 1-2 квада или треугольника, и в этом случае труд геморой с буферами совершенно не оправдывает себя – проще вызывать DPUP или DIPUP. В общем, оптимизация оптимизацией, но экономить на спичках не стоит – самый ценный ресурс, это ваше время, а вовсе не мощность видео-карты и/или компьютера. В конце-концов, ничего не мешает сделать отрисовку через DPUP/DIPUP, а если программа будет тормозить – тогда уже и оптимизировать.

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

Ещё по этой теме:




Раздел: DirectX 9, Featured · Теги: Direct3D, DirectX, Оптимизация, Создание движка

4 комментариев на "Vertex buffer, Index buffer"
  1. Antony пишет:

    Классно!

    А как обстоят дела в больших и серъёзных проектах: там для каждой модели описывают класс, который содержит VertexBuffer и IndexBuffer? Наверное, забегаю вперёд поезда? Тогда ждём продолжения)

    1. Вячеслав пишет:

      Antony, я очень постараюсь успеть уже сегодня дописать следующий урок и там всё объясню ;-)

      Если же отвечать на ваш вопрос кратко, то да. Чаще всего просто описывается один класс, который содержит в себе указатели на Vertex Buffer и соответствующий Index Buffer. Далее просто создаются объекты этого класса, в конструктор (или в функцию-лоадер) этого класса передаётся имя файла с моделью и объект класса её загружает. Т.е. получается один класс, много моделей и каждый объект, хоть они и одного класса все, может содержать в себе собственную, уникальную 3д-модель.

  2. Виталий пишет:

    Спасибо полезная информация!

  3. Виталий пишет:

    Спасибо полезная информация!

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

*

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>