Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Термины / Буфер вершин (Vertex Buffer)

Буфер вершин (Vertex Buffer)

Vertex Buffer (буфер вершин или вершинный буфер) — область данных, хранящая информацию обо всех или нескольких аттрибутах (элементах) вершины.

В библиотеке OpenGL существует непосредственный (Immediate mode) режим вывода геометрии без использования буферов вершин, задавая по очереди все необходимые атрибуты (элементы, в терминологии DirectX) каждой вершины последовательно. Такой способ вывода геометрии довольно медленный, а в некоторых графических GAPI, как DirectX или в новых версиях того же OpenGL, вообще отсутствует.

Буфер вершин позволяет создать блок с атрибутами большого количества вершин и выводить геометрию за один вызов определённых функций GAPI.

Отрисовка с использованием буфера вершин, расположенного в оперативной памяти


Для этого, в OpenGL следует установить указатели на различные атрибуты вершины следующими функциями:
//glVertexPointer рекомендуется ставить последним
void glVertexPointer( int size, enum type, sizei stride, void *pointer );
void glNormalPointer( enum type, sizei stride, void *pointer );
void glColorPointer( int size, enum type, sizei stride, void *pointer );
void glSecondaryColorPointer( int size, enum type, sizei stride, void *pointer );
void glTexCoordPointer( int size, enum type, sizei stride, void *pointer );
void glVertexAttribPointer( uint index, int size, enum type, boolean normalized,
                            sizei stride, const void *pointer );

Где pointer это указатель на данные, stride - шаг в байтах от одного атрибута до следующего (0, если они идут один за другим).

Более полный список и полное описание можно найти в спецификации OpenGL.
Так же, функциями glEnableClientState( enum array ) и glEnableVertexAttribArray( uint index ) следует указать что определённый массив активен.
Начиная с forward-compatible контекста GL3.0 и в более новых версиях, многие функции были отмечены устаревшими и теперь следует использовать только glVertexAttribPointer и glEnableVertexAttribArray.

Вывод геометрии в OpenGL производится следующими вызовами:

glDrawArrays( enum mode, int first, sizei count );
glMultiDrawArrays( enum mode, int *first, sizei *count, sizei primcount );
Первая функция отправляет count элементов буфера, начиная с first на отрисовку.
Вторая функция поможет заменить множество вызовов первой с разными параметрами first и count.


В Direct3D9 при отрисовке из оперативной памяти данные должны быть уложены одним куском, и формат вершины задаётся функциями IDirect3DDevice9::SetFVF или IDirect3DDevice9::SetVertexDeclaration.
Вывод выполняется следующей функцией:

IDirect3DDevice9::DrawPrimitiveUP( D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, 
                 CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride );
Где PrimitiveType — тип примитивов, PrimitiveCount — их количество, pVertexStreamZeroData — указатель на буфер и VertexStreamZeroStride — шаг в байтах от одного элемента буфера до следующего.


В Direct3D10 рисовать геометрию с использованием буфера в оперативной памяти нельзя.

Отрисовка с использованием буфера вершин, расположенного в видеопамяти


Данный вариант более эффективный, так как не приходится при каждом вызове отрисовки гонять буфер из оперативной памяти в память видеокарты.

В OpenGL, для создания буфера вершин в видеопамяти следует использовать расширение Vertex Buffer Object.
Создаём буфер:

glGenBuffersARB(1, &bufferID);
Устанавливаем, как буфер вершин и заполняем данными:
glBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, Length, Data, GL_STATIC_DRAW_ARB);
Где Length — размер буфера в байтах и Data — указатель на данные. Последний параметр указывает на то, как будет использоваться буфер, что может помочь драйверу разместить его наиболее эффективным образом.

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


В Direct3D9 буфер вершин создаётся следующим образом:

IDirect3DDevice9::CreateVertexBuffer( UINT Length, DWORD Usage, DWORD FVF,
                 D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle );
Где Length — размер буфера в байтах
Usage — один или комбинация D3DUSAGE флагов, например D3DUSAGE_DYNAMIC, означающий, что буфер планируется часто обновлять и D3DUSAGE_WRITEONLY, обозначающий, что мы только пишем в буфер, что позволяет драйверу ввести определённые оптимизации.
FVF — ноль, если используются шейдеры или fvf код, если идёт работа на FFP (Fixed Function Pipeline — конвейер с фиксированой функциональностью).
Pool — тип памяти, в которой будет расположен буфер. Обычно используются D3DPOOL_DEFAULT и D3DPOOL_MANAGED

Один из вариантов заполнения созданного буфера:

void* dest;
buffer->Lock(0, 0, &dest, 0);
memcpy(dest, Data, Length);
buffer->Unlock();

Установка буфера производится функцией (возможно одновременное использование нескольких буферов вершин, каждый из которых задаёт разные атрибуты)

IDirect3DDevice9::SetStreamSource( UINT StreamNumber, IDirect3DVertexBuffer9 * pStreamData,
                 UINT OffsetInBytes, UINT Stride );
Где StreamNumber — номер потока.
pStreamData — указатель на буфер.
OffsetInBytes — сдвиг от начала буфера в байтах.
Stride — шаг в байтах от одного элемента буфера до следующего.

Вывод геометрии теперь выполняется функцией

IDirect3DDevice9::DrawPrimitive( D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount );

Где PrimitiveType — тип примитивов, StartVertex — номер вершины, с которой начинать строить примитивы и PrimitiveCount — количество примитивов.


В Direct3D10 создать и заполнить буфер вершин можно следующим образом:
1) Создаём описание буфера.

// Создаём описание буфера
D3D10_BUFFER_DESC bufferDesc;
// Тип ресурса (DEFAULT - чтение и запись на GPU, IMMUTABLE - чтение на GPU,
// DYNAMIC - запись на CPU, чтение на GPU, STAGING - копирование из GPU на CPU)
bufferDesc.Usage = D3D10_USAGE_DEFAULT;
// Размер, в байтах
bufferDesc.ByteWidth = Length;
// Используется как буфер вершин
bufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
// Прочие флаги
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
2) Создаём буфер, одновременно заполняя его данными.
D3D10_SUBRESOURCE_DATA initData;
initData.pSysMem = Data;
device->CreateBuffer(&bufferDesc, &initData, &buffer);

Вывод неиндексированной геометрии выполняется функцией:

ID3D10Device::Draw( UINT VertexCount, UINT StartVertexLocation );

Вывод индексированной геометрии


Надо отметить, что ещё существует способ отрисовки геометрии с использованием Буфера индексов. Более подробно о нём и его преимуществах — в термине по указанной ссылке.

Что такое Буфер вершин (Vertex Buffer)?

12 июня 2009

#буферы, #Direct3D, #geometry, #OpenGL


Обновление: 21 апреля 2010

2001—2018 © GameDev.ru — Разработка игр