Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DirectX. Продвинутая Анимация (2004) [rus].pdf
Скачиваний:
335
Добавлен:
16.08.2013
Размер:
8.39 Mб
Скачать

342

Глава 12

После того как вы установили соответствующие альфа состояния, вы можете установить FVF, потоки, текстуры и визуализировать сцену!

//Установить вершинный шейдер и источники потоков pDevice->SetVertexShader(NULL); pDevice->SetFVF(PARTICLEFVF);

pDevice->SetStreamSource(0, pBuffer, 0, sizeof(sVertex));

//Установить текстуру

pDevice->SetTexture(0, &pTexture);

// Нарисовать частицу pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

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

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

Замечание.Демонстрационная программа Particles, расположенная на компакт-диске, иллюстрирует визуализацию большого количества частиц, используя только-чторас- смотренную технологию. Смотрите конец этой главы для получения дополнительной информации о программе Particles.

Работа с точечными спрайтами

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

Использованиечастицванимации

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

Помните, ранее в этой главе упоминалось, что квадратная частица требует четырех вершин. В предыдущей структуре sVertex использовалось двадцать вещественных значений и четыре значения DWORD на одну частицу. Итого: 96 байт данных для визуализации одной частицы! А как насчет точечных спрайтов?

Точечные спрайты используют следующую структуру вершин:

typedef struct {

D3DXVECTOR3 vecPos; // Координаты центра частицы float Size; // Размер частицы

D3DCOLOR Diffuse; // Рассеянный цвет } sPointSprite;

Выглядит очень похоже, разве нет?

Большим отличием является то, что для одной частицы необходима только одна структура sPointSprite. Так и есть, структура sPointSprite использует только 20 байт данных, что меньше чем sVertex на 76 байт. Какая экономия!

Так в чем же хитрость точечных спрайтов? Вы же знаете, что должны быть какие-нибудь недостатки, не так ли? Недостатком точечных спрайтов является ограниченность их размера. При использовании квадратов вы можете создавать частицы любого размера, точечные спрайты ограничены в максимальном размере, определяемом переменной D3DCAPS9::MaxPointSize. Это означает, что максимальный размер точечных спрайтов зависит от видео карты конечного пользователя.

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

Замечание. Для того чтобы убедиться, что вы можете аппаратно визуализировать точечные спрайты, необходимо проверить возможности аппаратного драйвера при помощи функции IDirect3D9::GetDeviceCaps. Если значение D3DCAPS9::MaxPointSize, полученное после вызова этой функции, установлено в 1.0, то тогда точечные спрайты не поддерживаются аппаратно.

Не будем брать во внимание недостатки, - точечные спрайты сохраняют огромное количество памяти; для тех видео карт, которые могут их использовать, это является превосходным решением для рисования частиц. Как вы видели в структуре вершин sPointSprite, точечные спрайты используют только четыре вещественных значения и одно DWORD для хранения координат, размера и рассеянного цвета частицы соответственно.

344

Глава 12

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

Точечные спрайты используют следующее объявление FVF:

#define POINTSPRITEFVF (D3DFVF_XYZ|D3DFVF_PSIZE|D3DFVF_DIFFUSE)

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

pDevice->CreateVertexBuffer(8 * sizeof(sPointSprite), \ D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, \ POINTSPRITEFVF, D3DPOOL_DEFAULT, \

&pBuffer, 0);

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

float Size = 10.0f; // Сделать размер частиц равным 10 единицам

sPointSprite PointSprites[8] = { // Частица #0

{ D3DXVECTOR3(0.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

// Частица #1

{ D3DXVECTOR3(10.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

// Частица #2

{ D3DXVECTOR3(22.0f,0.0f,0.0f), Size,

D3DCOLOR_RGBA(255,255,255,255) }, // Частица #3

{D3DXVECTOR3(30.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

// Частица #4

{ D3DXVECTOR3(-10.0f,0.0f,0.0f), Size,

D3DCOLOR_RGBA(255,255,255,255) }, // Частица #5

{ D3DXVECTOR3(-20.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

// Частица #6

{D3DXVECTOR3(-30.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

Использованиечастицванимации

// Частица #7

{D3DXVECTOR3(-40.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },

};

//Заблокировать буфер вершин sPointSprite *Ptr; pBuffer->Lock(0,0,(void**)&Ptr,0);

//Скопировать данные вершин в буфер memcpy(Ptr, PointSprites, sizeof(PointSprites));

//Разблокировать буфер вершин

pBuffer->Unlock();

После того как вы создали и заполнили буфер вершин данными точечного спрайта, можно визуализировать его. Подождите! Я забыл упомянуть об установке важных состояний визуализации. Direct3D должно знать, что вы используете точечные спрайты, расположенные в трехмерном пространстве (в противоположность экранному пространству). Для этого вы должны установить соответствующие состояния визуализации, как показано тут:

// Использовать всю текстуру для визуализации точечного спрайта pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);

// Масштабировать в пространстве камеры pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);

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

// Установить минимальный и определяемый по умолчанию размер точечного спрайта

pDevice->SetRenderState(D3DRS_POINTSIZE, FLOAT2DWORD(1.0f)); pDevice->SetRenderState(D3DRS_POINTSIZE_MIN, FLOAT2DWORD(0.0f));

Наконец необходимо установить несколько масштабируемых коэффициентов затухания, основанных на расстоянии. Direct3D сможет изменять размер частиц в зависимости от их удаленности от смотрящего. Здесь не нужно ничего необычного, так что значения, установленные по умолчанию (заданные в документации DirectX SDK) подойдут. Эти коэффициенты (которые фактически являются состояниями визуализации) устанавливаются при помощи следующего кода:

// Определить функцию, преобразующую float в DWORD

inline DWORD FLOAT2DWORD(FLOAT f) { return *((DWORD*)&f); }

346

// Установить значения затухания для масштабирования pDevice->SetRenderState(D3DRS_POINTSCALE_A, FLOAT2DWORD(1.0f)); pDevice->SetRenderState(D3DRS_POINTSCALE_B, FLOAT2DWORD(0.0f)); pDevice->SetRenderState(D3DRS_POINTSCALE_C, FLOAT2DWORD(0.0f));

Вы заметите кое-что забавное в последнем кусочке кодаиспользование функции FLOAT2DWORD. Как вы знаете, функция SetRenderState принимает только DWORD в качестве второго параметра. Значения коэффициентов затухания являются вещественными, так что приходится приводить их к типу DWORD. Вот здесь то и появляется FLOAT2DWORD. Используя эту функцию, вы можете указывать любое вещественное значения в качестве параметра функции SetRenderState и быть уверенным, что оно правильно преобразуется в DWORD.

Наконец можно визуализировать точечные спрайты! Помните, точечные спрайты являются обычными буферами вершин, использующими примитив типа точечный спрайт, указываемый флагомD3DPT_POINTLISTпри вызове функции DrawPrimitive. Не отвлекаясь, вот код, позволяющий включить альфа-тестирование и смешивание, установить FVF и источники потоков и вызвать функцию DrawPrimitive.

// Включить альфа-тестирование

pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); pDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);

//Включить альфа-комбинирование (простого добавочного типа) pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR); pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);

//Установить вершинный шейдер и источник потока

pDevice->SetVertexShader(NULL); pDevice->SetFVF(POINTSPRITEFVF);

pDevice->SetStreamSource(0, pBuffer, 0, sizeof(sPointSprite));

// Визуализировать точечный спрайт (восемь спрайтов) pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, 8);

Как вы можете видеть, работать с точечными спрайтами очень легко. По крайней мере намного проще, чем иметь дело с биллбордными квадратными полигонами, в спрайтах используется меньше данных. Единственной проблемой является то, что точечные спрайты ограничены в размерах и не полностью поддерживаются всеми видео-картами. Было бы очень хорошо, если бы была возможность использовать большие частицы и скорость визуализации точечных спрайтов, не правда ли? Замечательные новости - вы можете получить и то и другое при использовании вершинных шейдеров!

Соседние файлы в предмете Программирование на C++