ПрограммированиеСтатьиГрафика

Direct3D9: Урок 2: Представление вершин.

Автор:

Приложения, написанные под Microsoft Direct3D, используют вершины, чтобы рисовать геометрические фигуры. Каждая трёхмерная сцена включает одну и более геометрических фигур. Наш проект создаёт самую простую форму — треугольник, и выводит всё это на экран.

Эта обучающая программа показывает, как использовать вершины для создания треугольника. В уроке используются следующие шаги:

Шаги

Шаг 1: Определение типа вершин
Шаг 2: Установка Буфера Вершин
Шаг 3: Вывод на экран

Шаг 1: Определение типа вершин

Наш проект рисует двухмерный треугольник, используя три вершины. Это вводит понятие Буфера Вершин, который является Direct3D объектом, используемым для сохранения и отрисовки вершин. Вершины могут быть определены многими способами, специфичными для стандартной структуры вершин и переданы стандартным "гибким" форматом вершин (FVF). Формат вершин нашего проекта показан в следующем фрагменте кода.

struct CUSTOMVERTEX
{
   FLOAT x, y, z, rhw;   // Позиция вершины
   DWORD color;        // Цвет вершины
}

Вышеуказанная структура определяет формат стандартного типа вершин. Следующий шаг определяет FVF, который описывает содержание вершин в буфере вершин. Следующий код определяет FVF, который соответствует типу вершин, указанному выше.

#define D3DFVF_CUSTOMVERTEX(D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

D3DFVF описывает, какой тип вершин используется. Код выше использует флаги  D3DFVF_XYZRHW и D3DFVF_DIFFUSE, которые говорят буферу вершин, что стандартный тип вершин имеет преобразованную точку, сопровождаемую цветовым компонентом.

Теперь, когда определены стандартный векторный формат и FVF, мы должны заполнить буфер вершин самими вершинами, как описано в Шаге 2: Установка Буфера Вершин.

Примечание.  Вершины в нашем проекте преобразованы. Другими словами, они находятся в двухмерном пространстве и задаются двумя координатами. Здесь точка (0,0) находится в верхнем левом углу, ось Х направлена вправо, а ось Y - вниз. Эти вершины также являются освещёнными, т.е. они не используют освещение Direct3D, а используют свой собственный цвет.

Шаг 2: Установка Буфера Вершин

Теперь, когда стандартный формат вершин определён, пришло время инициализировать вершины. Наш проект делает это, вызывая определённую приложением функцию InitVB(), после создания требуемого Direct3D объекта. Следующий код инициализирует значения трёх стандартных вершин.

CUSTOMVERTEX vertices[] =
{
    { 150.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, },    // x, y, z, rhw, цвет
    { 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
    {  50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
};

Предыдущий код заполняет три вершины точками треугольника и определяет, в какой цвет красить каждую вершину. Первая точка имеет координаты (150, 150, 50) и окрашена в красный цвет (0xffff0000). Вторая точка имеет координаты (250, 250) и окрашена в зелёный цвет (0xff00ff00). Третья точка имеет координаты (50, 250) и окрашена в сине - зелёный цвет (0xff00ffff).  Каждая из этих точек имеет глубину 0.5 и RHW 1.0.

Следующий шаг вызывает IDirect3DDevice9::CreateVertexBuffer(), чтобы создать буфер вершин, как показано в следующем фрагменте.

if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),
         0 , D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB ) ) )
    return E_FAIL;

Первые два параметра IDirect3DDevice9::CreateVertexBuffer() говорят Direct3D желаемый размер и способ применения нового буфера вершин. Следующие два параметра определяют векторный формат и местоположение памяти для нового буфера. Векторный формат здесь - D3DFVF_CUSTOMVERTEX, который является "гибким" форматом вершин (FVF), который мы определили в коде раньше. Флаг D3DPOOL_DEFAULT говорит Direct3D создать буфер вершин в памяти, которая является наиболее соответствующей этому буферу. Последний параметр - адрес буфера вершин.

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

VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) ) )
    return E_FAIL;
memcpy( pVertices, vertices, sizeof(vertices) );
g_pVB->Unlock();

Сначала, буфер вершин захватывается методом IDirect3DVertexBuffer9::Lock(). Первый параметр - это смещение на данные вершины для блокировки в байтах. Второй параметр - размер данных вершины для блокировки в байтах. Третий параметр - адрес указателя на указатель на данные с вершинами. Четвёртый параметр говорит как захватывать (lock) данные из буфера вершин.

Далее вершины копируются в буфер вершин с помощью memcpy(). После того, как вершины помещены в вершинный буфер, вызывается IDirect3DVertexBuffer9::Unlock(), чтобы "отпустить" (unlock) вершинный буфер. Этот механизм lock и unlock требуется потому, что буфер вершин может быть в памяти устройства.

Теперь, когда вершинный буфер заполнен вершинами, пришло время произвести отрисовку экрана, как написано в Шаге 3: Вывод на экран.

Шаг 3: Вывод на экран

Теперь, когда буфер вершин заполнен вершинами, пришло время вывести всё на экран. Рендеринг экрана начинается с очистки заднего буфера в синий цвет и вызова BeginScene().

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0L );
g_pd3dDevice->BeginScene();

Рендеринг вершинных данных требует нескольких шагов. Сначала, вы должны установить "источник потока", в этом случае, используйте поток 0. Источник потока определяется вызовом IDirect3DDevice9::SetStreamSource().

g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );

Первый параметр IDirect3DDevice9::SetStreamSource() определяет источник потока данных устройства. Второй параметр - буфер вершины, связан с потоком данных. Третий параметр - размер одной вершины, в байтах. В предыдущем коде, размер CUSTOMVERTEX используется как этот размер.

В следующем шаге мы должны вызвать IDirect3DDevice9::SetFVF(), чтобы идентифицировать установленную функцию построения теней. Полные, стандартные вершинные шейдеры - довольно продвинутая тема, но в этом случае вершинные шейдеры - только гибкий формат вершин (FVF). Следующий код устанавливает код FVF.

g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

Единственный параметр для SetFVF - установленный код функции вершин, чтобы определить размещение данных вершины.

В следующем шаге мы используем IDirect3DDevice9::DrawPrimitive(), чтобы произвести рендеринг вершины в вершинном буфере, как показано в следующем коде.

g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );

Первый параметр, принимаемый DrawPrimitive() - флаг, который говорит Direct3D, какой тип примитива рисовать. Этот пример использует флаг D3DPT_TRIANGLELIST, чтобы определить список треугольников. Второй параметр - индекс первой вершины для загрузки. Третий параметр сообщает количество примитивов для отрисовки. Поскольку этот пример рисует только один треугольник, это значение установлено в 1.

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

g_pd3dDevice->EndScene();
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

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

В этой обучающей программе было показано, как использовать вершины для рисования геометрических фигур. Урок 3: Использование матриц вводит концепцию матриц и их использование.

Исходный код урока: d3d9_tut2.zip.

#Direct3D, #уроки, #основы

28 апреля 2003 (Обновление: 28 июня 2010)

Комментарии [9]