Повертаючись до гри з монстрами, можна використовувати частки для подання маленьких машин, що рухаються по вулицях міста. Простого текстурованого (з використання біллбордінга) квадратного полігону буде досить для цих машин, а що якщо замість цього використовувався б тривимірний меш? Він просто б зажадав візуалізації декількох додаткових багатокутників в кожному кадрі, і, повірте мені, ефект від цих маленьких машин, що рухаються по місту, коштував би додаткового часу візуалізації.
Добре, якщо не торкатися візуалізації мешів, то велика частина змальованих частинок буде складатися з квадратних полігонів. Ви можете малювати їх різними способами, але в цій книзі я покажу вам три. Перший метод малювання частинок, напевно, є найпростішим, але як ви скоро побачите, він має свої недоліки.
Малювання частинок настільки ж просто, наскільки й малювання багатокутників, тому що частка - це просто міняє розміри текстурований квадратний полігон. На рис. 12.4 показаний зовнішній вигляд двох трикутників, які використовуються для створення частинок. На цьому малюнку я показав частку, що має розмір 10 одиниць.
Мал. 12.4. Частка, що має розмір 10 одиниць, має протяжність 5 одиниць в напрямах осей х і у
На додаток до координат вершин, використовуваним при малюванні частки,
необхідна ще пара речей. По-перше, необхідна текстура, яка використовується для поліпшення зовнішнього вигляду частки. Чи є ця текстура димом, згустком світла або переляканим людиною, вам необхідно зберігати картинку в об'єкті текстури. Крім текстур багатокутників необхідна інформація про текстурних координатах для накладення текстури на багатокутник.
Для спрощення, я буду використовувати тільки одну текстуру для кожного типу частинок в цьому розділі. Іншими словами, якщо є частинки диму і вогню, я завантажений дві текстури. Будь екземпляр будь-якої частинки буде використовувати власну текстуру при візуалізації. Можливо ви захочете об'єднати всі текстури частинок в одну, для поліпшення частинок.
Наступне, що вам необхідно для створення даних багатокутника частинок, це розсіяна (diffuse) складова кольору. Можливість змінювати колір частинок під час виконання дуже корисна, тому що зміни кольору можуть представляти різні цикли життя частинок. Наприклад, вогонь повільно охолоджується і змінює свій колір у міру того, як він віддаляється від джерела тепла. Замість використання безлічі текстур для представлення різних рівнів нагріву ви можете використовувати одну і ту ж текстуру і просто міняти розсіяний колір частки.
Останнє, що вам потрібно, це розмір частки. Загалом, частинки можуть мати будь-який розмір, від невеликого плями пилу до метеора, крушать Землю. Для визначення розміру частки вам необхідно вибрати габарити частки, використовуючи ті ж світові координати, що використовують тривимірні меши.
Припустимо, ви хочете, щоб частка була 20 одиниць в ширину і 50 одиниць в висоту. Цей розмір застосовується тільки до осей х і у (т. К. На насправді частка є плоским об'єктом, який завжди спрямований до дивиться). При створенні частки її центр розташовується на початку координат світу. Використовуючи розміри частки, ви можете створити вершини, що представляють її кути. Ці вершини розташовуються, використовуючи розміри частки, поділені навпіл, як зсув. Наприклад, частка розмірів 20x50 лежить від-10 до 10 на осі х і від-25 до 25 на осі у.
Ось і все про це, тепер ви повинні мати у своєму розпорядженні достатню кількість інформації, щоб почати малювати частки! Підсумуємо: необхідно мати розмір і координати вершин частки (використовуючи розмір в якості бази), текстурні координати і розсіяну складову кольору для кожної вершини. Сміливіше, об'єднайте всі ці компоненти в одну структуру вершин, як я зробив тут:
D3DXVECTOR3 vecPos; // Координати вершини частки D3DCOLOR Diffuse; // Розсіяний колір
float u, v; // Текстерно координати> sVertex;
#define VERTEXFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
Використовуючи структуру вершин і FVF, ви можете створити невеликий буфер вершин, який містив би досить вершин для малювання однієї частинки. Для частки використовуються два трикутника, це означає, що потрібно створити шість вершин (три для кожного трикутника). Використовуючи смугу трикутників, можна скоротити кількість вершин до чотирьох.
Буфер вершин можна створити, використовуючи наступний код:
IDirect3DVertexBuffer9 * pVB = NULL; pDevice-> CreateVertexBuffer (4 * sizeof (sVertex), \
D3DUSAGE_WRITEONLY, \ VERTEXFVF, D3DPOOL_DEFAULT, \ pVB, NOLL);
Після того як ви створили буфер вершин (він створюється один раз в програмі), ви можете заповнити його даними частинки. Припустимо, ви хочете намалювати частку, що має розмір 10 одиниць (і в напрямку осі х і у напрямку осі у), використовуючи всю поверхню текстури, що має білий колір. Для цього вам необхідно використовувати наступний код:
// Size = розмір частки, в даному випадку 10.0 float Size = 10.0;
// Отримати розмір, поділений навпіл, для установки координат вершин float HalfSize = Size / 2.0f;
// Заблокувати буфер вершин і заповнити його даними вершин sVertex * Vertex = NULL;
pVB-> Lock (0, 0, (void **) Vertex, 0);
// Верхній лівий кут, вершина номер 0
pVB [0] .vecPos = D3DXVECTOR3 (-Size, Size, 0.0f); pVB [0] .Diffuse = D3DCOLOR_RGBA (255,255,255,255); pVB [0] .u = 0.0f; pVB [0] .v = 0.0f;
// Верхній правий кут, вершина номер 1 pVB [1] .vecPos = D3DXVECTOR3 (Size, Size, 0.0f); pVB [1] .Diffuse = D3DCOLOR_RGBA (255,255,255,255); pVB [1] .u = 1.0f; pVB [1] .v = 0.0f;
// Нижній лівий кут, вершина номер 2 pVB [2] .vecPos = D3DXVECTOR3 (-Size, -Size, 0.0f); pVB [2] .Diffuse = D3DCOLOR_RGBA (255,255,255,255); pVB [2] .u = 0.0f; pVB [2] .v = 1.0f;
// Нижній правий кут, вершина номер 3 pVB [3] .vecPos = D3DXVECTOR3 (Size, -Size, 0.0f); pVB [3] .Diffuse = D3DCOLOR_RGBA (255,255,255,255); pVB [3] .u = 1.0f; pVB [3] .v = 1.0f;
// Розблокувати буфер вершин
Тепер верховий буфер готовий до візуалізації. Однак є невелика тонкість. Ви помітите, що координати вершин у своєму розпорядженні багатокутники в центрі координат тривимірного світу, розширюючись в напрямку осей х і у. Т. к. Точка огляду може знаходиться де завгодно в світі, необхідно розташувати багатокутники, використовуючи перетворення світу перед візуалізацією.
Також необхідно повернути багатокутники таким чином, щоб вони були спрямовані на наглядача, що, як ви пам'ятаєте, є метою біллбордінга. Необхідно обчислити білборд-перетворення, щоб повернути багатокутники
до дивиться. Використовуючи це перетворення, ви додаєте координати частинки
в місце, де вона повинні бути намальована (в світових координатах).
Попередження. Використання функції GetTransform для отримання перетворення Direct3D сильно замедляетработу і не завжди можливо. Найкраще зберігати глобальниепреобразованіяміра, відаіпроекціі, коториеможнопотоміспользовать.Однако покаятися піду поганим шляхом і буду використовувати GetTransform вучебних цілях.
Для створення білборд-перетворення необхідно отримати матрицю перетворення виду і обчислити зворотну їй матрицю (таким чином змінюючи порядок містяться в ній перетворень на зворотний), використовуючи функцію D3DXMatrixInverse, як показано тут:
// Отримати матрицю перетворення виду і звернути її D3DXMATRIX matView;
pDevice-> GetTransform (D3DTS_VIEW, matView); D3DXMatrixInverse (matView, NULL, matView);
Використання зворотного перетворення дозволить обертати вершини частки в напрямку, протилежному напрямку виду, таким чином вирівнюючи координати до дивиться. Після отримання зворотного перетворення виду необхідно безпосередньо додати координати частинки для розташування її в тривимірному світі. Ви можете зробити це, зберігши координати х, у і z в елементах _41, _42 і_43 відповідно тільки що обчисленої зворотного матриці перетворення і встановивши результуючу матрицю перетворення в якості світового перетворення.
// Покладемо ParticleXPos, ParticleYPos і ParticleZPos містять світові
// координати рисуемой частки. Додати координати рисуемой частки matView._41 = ParticleXPos;
matView._42 = ParticleYPos; matView._43 = ParticleZPos;
// Установити результуючу матрицю як перетворення світу pDevice-> SetTransform (D3DTS_WORLD, matView);
Після того як ви встановили матрицю перетворення світу, можна візуалізувати багатокутники. Для того щоб частки комбінувалися зі сценою, необхідно переконатися, що використовується z-буфер і альфа-тестування. Використання z-буфера дозволяє переконатися, що частинки коректно відображаються в сцені, а альфа-тестування дозволяє переконатися в тому, що прозорі частини текстури частки не малюються (дозволяючи бачити залишилася геометрію через ці прозорі частини). Також ви можете включити альфа змішування, якщо хочете створити деякі ефекти змішування кольорів.
Пропустивши установку z-буфера (ви повинні були зробити її раніше), ви можете включити альфа тестування і альфа змішування так:
// Включити альфа тестування
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);
Що стосується альфа-тестування, я вибрав використання правила порівняння більше або дорівнює. Це означає, що якщо пікселі текстури частки мають значення альфа яка дорівнює або перевищує 8, то вони візуалізуються, в іншому ж випадку вони пропускаються. Використання альфа-тестування означає необхідність використання функції D3DXCreateTextureFromFileEx для завантаження текстур, задавши колірної режим, який використовує альфа канали (такий як D3DFMT_A8R8G8B8), і колірної ключ непрозорого чорного (D3DCOLOR_RGBA (0,0,0,255)), як показано в наступному шматочку коду:
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX DEFAULT, D3DCOLOR_RGBA (0,0,0,255), NULL, NULL, pTexture);